diff --git a/src/main/java/us/myles/ViaVersion/chunks/Chunk.java b/src/main/java/us/myles/ViaVersion/chunks/Chunk.java index 8168cd1b1..e57029742 100644 --- a/src/main/java/us/myles/ViaVersion/chunks/Chunk.java +++ b/src/main/java/us/myles/ViaVersion/chunks/Chunk.java @@ -1,10 +1,9 @@ package us.myles.ViaVersion.chunks; -import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; -@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +@RequiredArgsConstructor @Getter public class Chunk { private final int x; @@ -21,7 +20,7 @@ public class Chunk { * @param x coord * @param z coord */ - protected Chunk(int x, int z) { + public Chunk(int x, int z) { this(x, z, true, 0, new ChunkSection[16], null); this.unloadPacket = true; } diff --git a/src/main/java/us/myles/ViaVersion/packets/PacketType.java b/src/main/java/us/myles/ViaVersion/packets/PacketType.java index 340db1679..3bf0bc66a 100644 --- a/src/main/java/us/myles/ViaVersion/packets/PacketType.java +++ b/src/main/java/us/myles/ViaVersion/packets/PacketType.java @@ -92,7 +92,7 @@ public enum PacketType { PLAY_UNLOAD_CHUNK(State.PLAY, Direction.OUTGOING, -1, 0x1D), PLAY_CHANGE_GAME_STATE(State.PLAY, Direction.OUTGOING, 0x2B, 0x1E), PLAY_KEEP_ALIVE(State.PLAY, Direction.OUTGOING, 0x00, 0x1F), // Mapped - PLAY_CHUNK_DATA(State.PLAY, Direction.OUTGOING, 0x21, 0x20), // TODO + PLAY_CHUNK_DATA(State.PLAY, Direction.OUTGOING, 0x21, 0x20), // Mapped PLAY_EFFECT(State.PLAY, Direction.OUTGOING, 0x28, 0x21), // Mapped PLAY_PARTICLE(State.PLAY, Direction.OUTGOING, 0x2A, 0x22), // Mapped PLAY_JOIN_GAME(State.PLAY, Direction.OUTGOING, 0x01, 0x23), // Mapped diff --git a/src/main/java/us/myles/ViaVersion2/api/PacketWrapper.java b/src/main/java/us/myles/ViaVersion2/api/PacketWrapper.java index cd8178e8e..09b883a55 100644 --- a/src/main/java/us/myles/ViaVersion2/api/PacketWrapper.java +++ b/src/main/java/us/myles/ViaVersion2/api/PacketWrapper.java @@ -45,7 +45,7 @@ public class PacketWrapper { throw new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index); } - public T read(Type type) { + public T read(Type type) throws Exception { System.out.println("Reading: " + type.getTypeName()); // We could in the future log input read values, but honestly for things like bulk maps, mem waste D: return type.read(inputBuffer); @@ -57,13 +57,13 @@ public class PacketWrapper { packetValues.add(new Pair(type, value)); } - public T passthrough(Type type) { + public T passthrough(Type type) throws Exception { T value = read(type); write(type, value); return value; } - public void writeToBuffer(ByteBuf buffer) { + public void writeToBuffer(ByteBuf buffer) throws Exception { for (Pair packetValue : packetValues) { packetValue.getKey().write(buffer, packetValue.getValue()); } diff --git a/src/main/java/us/myles/ViaVersion2/api/item/Item.java b/src/main/java/us/myles/ViaVersion2/api/item/Item.java index c850a713f..71c972a92 100644 --- a/src/main/java/us/myles/ViaVersion2/api/item/Item.java +++ b/src/main/java/us/myles/ViaVersion2/api/item/Item.java @@ -1,4 +1,14 @@ package us.myles.ViaVersion2.api.item; +import lombok.Getter; +import lombok.Setter; +import org.spacehq.opennbt.tag.builtin.CompoundTag; + +@Getter +@Setter public class Item { + private short id; + private byte amount; + private short data; + private CompoundTag tag; } diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol/Protocol.java b/src/main/java/us/myles/ViaVersion2/api/protocol/Protocol.java index 48a7fa40f..0bce245c8 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol/Protocol.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol/Protocol.java @@ -47,7 +47,7 @@ public abstract class Protocol { outgoing.put(new Pair<>(state, oldPacketID), protocolPacket); } - public void transform(Direction direction, State state, int packetID, PacketWrapper packetWrapper, ByteBuf output) { + public void transform(Direction direction, State state, int packetID, PacketWrapper packetWrapper, ByteBuf output) throws Exception { Pair statePacket = new Pair<>(state, packetID); Map, ProtocolPacket> packetMap = (direction == Direction.OUTGOING ? outgoing : incoming); ProtocolPacket protocolPacket; diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/Protocol1_9TO1_8.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/Protocol1_9TO1_8.java index f09c592c7..e69db5733 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/Protocol1_9TO1_8.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/Protocol1_9TO1_8.java @@ -7,6 +7,7 @@ import us.myles.ViaVersion2.api.data.UserConnection; import us.myles.ViaVersion2.api.metadata.Metadata; import us.myles.ViaVersion2.api.protocol.Protocol; import us.myles.ViaVersion2.api.protocol1_9to1_8.packets.*; +import us.myles.ViaVersion2.api.protocol1_9to1_8.storage.ClientChunks; import us.myles.ViaVersion2.api.protocol1_9to1_8.storage.EntityTracker; import us.myles.ViaVersion2.api.protocol1_9to1_8.types.MetadataListType; import us.myles.ViaVersion2.api.protocol1_9to1_8.types.MetadataType; @@ -57,5 +58,7 @@ public class Protocol1_9TO1_8 extends Protocol { public void init(UserConnection userConnection) { // Entity tracker userConnection.put(new EntityTracker()); + // Chunk tracker + userConnection.put(new ClientChunks()); } } diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/EntityPackets.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/EntityPackets.java index d4ba00067..774ac0eb3 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/EntityPackets.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/EntityPackets.java @@ -174,7 +174,7 @@ public class EntityPackets { map(Type.VAR_INT); // 1 - Action Type handler(new PacketHandler() { @Override - public void handle(PacketWrapper wrapper) { + public void handle(PacketWrapper wrapper) throws Exception { int type = wrapper.get(Type.VAR_INT, 1); if (type == 2) { wrapper.passthrough(Type.FLOAT); // 2 - X diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/PlayerPackets.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/PlayerPackets.java index ee98d18dc..544526ea4 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/PlayerPackets.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/PlayerPackets.java @@ -49,7 +49,7 @@ public class PlayerPackets { // We only handle if the title or subtitle is set then just write through. handler(new PacketHandler() { @Override - public void handle(PacketWrapper wrapper) { + public void handle(PacketWrapper wrapper) throws Exception { int action = wrapper.get(Type.VAR_INT, 0); if (action == 0 || action == 1) { Protocol1_9TO1_8.FIX_JSON.write(wrapper, wrapper.read(Type.STRING)); @@ -90,7 +90,7 @@ public class PlayerPackets { map(Type.BYTE); handler(new PacketHandler() { @Override - public void handle(PacketWrapper wrapper) { + public void handle(PacketWrapper wrapper) throws Exception { byte mode = wrapper.get(Type.BYTE, 1); if (mode == 0 || mode == 2) { wrapper.passthrough(Type.STRING); @@ -152,7 +152,7 @@ public class PlayerPackets { handler(new PacketHandler() { @Override - public void handle(PacketWrapper wrapper) { + public void handle(PacketWrapper wrapper) throws Exception { int action = wrapper.get(Type.VAR_INT, 0); int count = wrapper.get(Type.VAR_INT, 1); diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/SpawnPackets.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/SpawnPackets.java index 56e68e51b..ba747cfd0 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/SpawnPackets.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/SpawnPackets.java @@ -61,7 +61,7 @@ public class SpawnPackets { // Create last 3 shorts create(new ValueCreator() { @Override - public void write(PacketWrapper wrapper) { + public void write(PacketWrapper wrapper) throws Exception { int data = wrapper.get(Type.INT, 3); // Data (4th Integer) short vX = 0, vY = 0, vZ = 0; diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/WorldPackets.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/WorldPackets.java index 5633e1b69..625da36fa 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/WorldPackets.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/packets/WorldPackets.java @@ -1,8 +1,12 @@ package us.myles.ViaVersion2.api.protocol1_9to1_8.packets; import us.myles.ViaVersion.packets.State; +import us.myles.ViaVersion2.api.PacketWrapper; import us.myles.ViaVersion2.api.protocol.Protocol; import us.myles.ViaVersion2.api.protocol1_9to1_8.Protocol1_9TO1_8; +import us.myles.ViaVersion2.api.protocol1_9to1_8.storage.ClientChunks; +import us.myles.ViaVersion2.api.protocol1_9to1_8.types.ChunkType; +import us.myles.ViaVersion2.api.remapper.PacketHandler; import us.myles.ViaVersion2.api.remapper.PacketRemapper; import us.myles.ViaVersion2.api.type.Type; @@ -43,6 +47,20 @@ public class WorldPackets { } }); + // Chunk Packet + protocol.registerOutgoing(State.PLAY, 0x21, 0x20, new PacketRemapper() { + @Override + public void registerMap() { + handler(new PacketHandler() { + @Override + public void handle(PacketWrapper wrapper) throws Exception{ + ClientChunks clientChunks = wrapper.user().get(ClientChunks.class); + wrapper.passthrough(new ChunkType(clientChunks)); + } + }); + } + }); + /* Packets which do not have any field remapping or handlers */ protocol.registerOutgoing(State.PLAY, 0x25, 0x08); // Block Break Animation Packet @@ -58,8 +76,6 @@ public class WorldPackets { protocol.registerOutgoing(State.PLAY, 0x03, 0x44); // Update Time Packet protocol.registerOutgoing(State.PLAY, 0x44, 0x35); // World Border Packet - // TODO: Chunk Data, Bulk Chunk :) - /* Incoming Packets */ // Sign Update Request Packet diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/storage/ClientChunks.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/storage/ClientChunks.java new file mode 100644 index 000000000..dfe96fc7f --- /dev/null +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/storage/ClientChunks.java @@ -0,0 +1,13 @@ +package us.myles.ViaVersion2.api.protocol1_9to1_8.storage; + +import com.google.common.collect.Sets; +import lombok.Getter; +import us.myles.ViaVersion2.api.data.StoredObject; + +import java.util.Set; + +@Getter +public class ClientChunks extends StoredObject { + private final Set loadedChunks = Sets.newConcurrentHashSet(); + private final Set bulkChunks = Sets.newConcurrentHashSet(); +} diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/ChunkType.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/ChunkType.java new file mode 100644 index 000000000..29a609405 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/ChunkType.java @@ -0,0 +1,162 @@ +package us.myles.ViaVersion2.api.protocol1_9to1_8.types; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.bukkit.Bukkit; +import us.myles.ViaVersion.chunks.Chunk; +import us.myles.ViaVersion.chunks.ChunkSection; +import us.myles.ViaVersion.util.PacketUtil; +import us.myles.ViaVersion2.api.protocol1_9to1_8.storage.ClientChunks; +import us.myles.ViaVersion2.api.type.PartialType; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.ShortBuffer; +import java.util.BitSet; +import java.util.logging.Level; + +public class ChunkType extends PartialType { + /** + * Amount of sections in a chunk. + */ + private static final int SECTION_COUNT = 16; + /** + * size of each chunk section (16x16x16). + */ + private static final int SECTION_SIZE = 16; + /** + * Length of biome data. + */ + private static final int BIOME_DATA_LENGTH = 256; + + public ChunkType(ClientChunks chunks) { + super(chunks, Chunk.class); + } + + @Override + public Chunk read(ByteBuf input, ClientChunks param) { + int chunkX = input.readInt(); + int chunkZ = input.readInt(); + long chunkHash = toLong(chunkX, chunkZ); + boolean groundUp = input.readByte() != 0; + int bitmask = input.readUnsignedShort(); + int dataLength = PacketUtil.readVarInt(input); + + // Data to be read + BitSet usedSections = new BitSet(16); + ChunkSection[] sections = new ChunkSection[16]; + byte[] biomeData = null; + + // Calculate section count from bitmask + for (int i = 0; i < 16; i++) { + if ((bitmask & (1 << i)) != 0) { + usedSections.set(i); + } + } + int sectionCount = usedSections.cardinality(); // the amount of sections set + + // If the chunk is from a chunk bulk, it is never an unload packet + // Other wise, if it has no data, it is :) + boolean isBulkPacket = param.getBulkChunks().remove(chunkHash); + if (sectionCount == 0 && groundUp && !isBulkPacket && param.getLoadedChunks().contains(chunkHash)) { + // This is a chunk unload packet + param.getLoadedChunks().remove(chunkHash); + return new Chunk(chunkX, chunkZ); + } + + int startIndex = input.readerIndex(); + param.getLoadedChunks().add(chunkHash); // mark chunk as loaded + + // Read blocks + for (int i = 0; i < SECTION_COUNT; i++) { + if (!usedSections.get(i)) continue; // Section not set + ChunkSection section = new ChunkSection(); + sections[i] = section; + + // Read block data and convert to short buffer + byte[] blockData = new byte[ChunkSection.SIZE * 2]; + input.readBytes(blockData); + ShortBuffer blockBuf = ByteBuffer.wrap(blockData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); + + for (int j = 0; j < ChunkSection.SIZE; j++) { + int mask = blockBuf.get(); + int type = mask >> 4; + int data = mask & 0xF; + section.setBlock(j, type, data); + } + } + + // Read block light + for (int i = 0; i < SECTION_COUNT; i++) { + if (!usedSections.get(i)) continue; // Section not set, has no light + byte[] blockLightArray = new byte[ChunkSection.LIGHT_LENGTH]; + input.readBytes(blockLightArray); + sections[i].setBlockLight(blockLightArray); + } + + // Read sky light + int bytesLeft = dataLength - (input.readerIndex() - startIndex); + if (bytesLeft >= ChunkSection.LIGHT_LENGTH) { + for (int i = 0; i < SECTION_COUNT; i++) { + if (!usedSections.get(i)) continue; // Section not set, has no light + byte[] skyLightArray = new byte[ChunkSection.LIGHT_LENGTH]; + input.readBytes(skyLightArray); + sections[i].setSkyLight(skyLightArray); + bytesLeft -= ChunkSection.LIGHT_LENGTH; + } + } + + // Read biome data + if (bytesLeft >= BIOME_DATA_LENGTH) { + biomeData = new byte[BIOME_DATA_LENGTH]; + input.readBytes(biomeData); + bytesLeft -= BIOME_DATA_LENGTH; + } + + // Check remaining bytes + if (bytesLeft > 0) { + Bukkit.getLogger().log(Level.WARNING, bytesLeft + " Bytes left after reading chunk! (" + groundUp + ")"); + } + + // Return chunk + return new Chunk(chunkX, chunkZ, groundUp, bitmask, sections, biomeData); + } + + @Override + public void write(ByteBuf output, ClientChunks param, Chunk chunk) { + if(chunk.isUnloadPacket()) { + output.clear(); + PacketUtil.writeVarInt(0x1D, output); // Unload packet ID + } + + // Write primary info + output.writeInt(chunk.getX()); + output.writeInt(chunk.getZ()); + if(chunk.isUnloadPacket()) return; + output.writeByte(chunk.isGroundUp() ? 0x01 : 0x00); + PacketUtil.writeVarInt(chunk.getPrimaryBitmask(), output); + + ByteBuf buf = Unpooled.buffer(); + for(int i = 0; i < SECTION_COUNT; i++) { + ChunkSection section = chunk.getSections()[i]; + if(section == null) continue; // Section not set + section.writeBlocks(buf); + section.writeBlockLight(buf); + if(!section.hasSkyLight()) continue; // No sky light, we're done here. + section.writeSkyLight(buf); + } + buf.readerIndex(0); + PacketUtil.writeVarInt(buf.readableBytes() + (chunk.hasBiomeData() ? 256 : 0), output); + output.writeBytes(buf); + buf.release(); // release buffer + + // Write biome data + if(chunk.hasBiomeData()) { + output.writeBytes(chunk.getBiomeData()); + } + } + + private static long toLong(int msw, int lsw) { + return ((long) msw << 32) + lsw - -2147483648L; + } +} diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataListType.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataListType.java index 7be6e913d..b7d3af678 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataListType.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataListType.java @@ -14,7 +14,7 @@ public class MetadataListType extends Type> { } @Override - public List read(ByteBuf buffer) { + public List read(ByteBuf buffer) throws Exception { List list = new ArrayList<>(); Metadata m; do { @@ -28,8 +28,8 @@ public class MetadataListType extends Type> { } @Override - public void write(ByteBuf buffer, List object) { - for(Metadata m:object){ + public void write(ByteBuf buffer, List object) throws Exception { + for (Metadata m : object) { Protocol1_9TO1_8.METADATA.write(buffer, m); } // Write end of list diff --git a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataType.java b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataType.java index b17625b2f..f60e51884 100644 --- a/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataType.java +++ b/src/main/java/us/myles/ViaVersion2/api/protocol1_9to1_8/types/MetadataType.java @@ -13,7 +13,7 @@ public class MetadataType extends Type { } @Override - public Metadata read(ByteBuf buffer) { + public Metadata read(ByteBuf buffer) throws Exception { byte item = buffer.readByte(); if (item == 127) return null; // end of metadata MetadataTypes type = MetadataTypes.byId((item & 0xE0) >> 5); @@ -22,7 +22,7 @@ public class MetadataType extends Type { } @Override - public void write(ByteBuf buffer, Metadata object) { + public void write(ByteBuf buffer, Metadata object) throws Exception { if (object == null) { buffer.writeByte(127); } else { diff --git a/src/main/java/us/myles/ViaVersion2/api/remapper/PacketHandler.java b/src/main/java/us/myles/ViaVersion2/api/remapper/PacketHandler.java index 1e486e7b5..55668cc17 100644 --- a/src/main/java/us/myles/ViaVersion2/api/remapper/PacketHandler.java +++ b/src/main/java/us/myles/ViaVersion2/api/remapper/PacketHandler.java @@ -3,10 +3,10 @@ package us.myles.ViaVersion2.api.remapper; import us.myles.ViaVersion2.api.PacketWrapper; public abstract class PacketHandler implements ValueWriter { - public abstract void handle(PacketWrapper wrapper); + public abstract void handle(PacketWrapper wrapper) throws Exception; @Override - public void write(PacketWrapper writer, Object inputValue) { + public void write(PacketWrapper writer, Object inputValue) throws Exception { handle(writer); } } diff --git a/src/main/java/us/myles/ViaVersion2/api/remapper/PacketRemapper.java b/src/main/java/us/myles/ViaVersion2/api/remapper/PacketRemapper.java index 5005e40a1..6d68aa497 100644 --- a/src/main/java/us/myles/ViaVersion2/api/remapper/PacketRemapper.java +++ b/src/main/java/us/myles/ViaVersion2/api/remapper/PacketRemapper.java @@ -41,7 +41,7 @@ public abstract class PacketRemapper { public abstract void registerMap(); - public void remap(PacketWrapper packetWrapper) { + public void remap(PacketWrapper packetWrapper) throws Exception{ // Read all the current values for (Pair valueRemapper : valueRemappers) { Object object = valueRemapper.getKey().read(packetWrapper); diff --git a/src/main/java/us/myles/ViaVersion2/api/remapper/TypeRemapper.java b/src/main/java/us/myles/ViaVersion2/api/remapper/TypeRemapper.java index 148c3ea8e..8b23117a7 100644 --- a/src/main/java/us/myles/ViaVersion2/api/remapper/TypeRemapper.java +++ b/src/main/java/us/myles/ViaVersion2/api/remapper/TypeRemapper.java @@ -11,7 +11,7 @@ public class TypeRemapper implements ValueReader, ValueWriter { } @Override - public T read(PacketWrapper wrapper) { + public T read(PacketWrapper wrapper) throws Exception { return wrapper.read(type); } diff --git a/src/main/java/us/myles/ViaVersion2/api/remapper/ValueCreator.java b/src/main/java/us/myles/ViaVersion2/api/remapper/ValueCreator.java index 30d475527..00952ed1a 100644 --- a/src/main/java/us/myles/ViaVersion2/api/remapper/ValueCreator.java +++ b/src/main/java/us/myles/ViaVersion2/api/remapper/ValueCreator.java @@ -3,10 +3,10 @@ package us.myles.ViaVersion2.api.remapper; import us.myles.ViaVersion2.api.PacketWrapper; public abstract class ValueCreator implements ValueWriter { - public abstract void write(PacketWrapper wrapper); + public abstract void write(PacketWrapper wrapper) throws Exception; @Override - public void write(PacketWrapper writer, Object inputValue) { + public void write(PacketWrapper writer, Object inputValue) throws Exception { write(writer); } } diff --git a/src/main/java/us/myles/ViaVersion2/api/remapper/ValueReader.java b/src/main/java/us/myles/ViaVersion2/api/remapper/ValueReader.java index 81326ea72..042eb4845 100644 --- a/src/main/java/us/myles/ViaVersion2/api/remapper/ValueReader.java +++ b/src/main/java/us/myles/ViaVersion2/api/remapper/ValueReader.java @@ -4,5 +4,5 @@ import io.netty.buffer.ByteBuf; import us.myles.ViaVersion2.api.PacketWrapper; public interface ValueReader { - public T read(PacketWrapper wrapper); + public T read(PacketWrapper wrapper) throws Exception; } diff --git a/src/main/java/us/myles/ViaVersion2/api/remapper/ValueWriter.java b/src/main/java/us/myles/ViaVersion2/api/remapper/ValueWriter.java index ad2f528c1..ad7dff859 100644 --- a/src/main/java/us/myles/ViaVersion2/api/remapper/ValueWriter.java +++ b/src/main/java/us/myles/ViaVersion2/api/remapper/ValueWriter.java @@ -3,5 +3,5 @@ package us.myles.ViaVersion2.api.remapper; import us.myles.ViaVersion2.api.PacketWrapper; public interface ValueWriter { - public void write(PacketWrapper writer, T inputValue); + public void write(PacketWrapper writer, T inputValue) throws Exception; } diff --git a/src/main/java/us/myles/ViaVersion2/api/type/ByteBufReader.java b/src/main/java/us/myles/ViaVersion2/api/type/ByteBufReader.java index 88359c6a9..26befd28a 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/ByteBufReader.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/ByteBufReader.java @@ -3,5 +3,5 @@ package us.myles.ViaVersion2.api.type; import io.netty.buffer.ByteBuf; public interface ByteBufReader { - public T read(ByteBuf buffer); + public T read(ByteBuf buffer) throws Exception; } diff --git a/src/main/java/us/myles/ViaVersion2/api/type/ByteBufWriter.java b/src/main/java/us/myles/ViaVersion2/api/type/ByteBufWriter.java index 570fabb5c..fd376e7cc 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/ByteBufWriter.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/ByteBufWriter.java @@ -3,5 +3,5 @@ package us.myles.ViaVersion2.api.type; import io.netty.buffer.ByteBuf; public interface ByteBufWriter { - public void write(ByteBuf buffer, T object); + public void write(ByteBuf buffer, T object) throws Exception; } diff --git a/src/main/java/us/myles/ViaVersion2/api/type/PartialType.java b/src/main/java/us/myles/ViaVersion2/api/type/PartialType.java new file mode 100644 index 000000000..63e6ae540 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion2/api/type/PartialType.java @@ -0,0 +1,26 @@ +package us.myles.ViaVersion2.api.type; + +import io.netty.buffer.ByteBuf; + +public abstract class PartialType extends Type { + private final X param; + + public PartialType(X param, Class type) { + super(type); + this.param = param; + } + + public abstract T read(ByteBuf buffer, X param); + + public abstract void write(ByteBuf buffer, X param, T object); + + @Override + public T read(ByteBuf buffer) { + return read(buffer, this.param); + } + + @Override + public void write(ByteBuf buffer, T object) { + write(buffer, this.param, object); + } +} diff --git a/src/main/java/us/myles/ViaVersion2/api/type/Type.java b/src/main/java/us/myles/ViaVersion2/api/type/Type.java index 52eb641fd..3eaff4e45 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/Type.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/Type.java @@ -4,6 +4,7 @@ package us.myles.ViaVersion2.api.type; import lombok.Getter; import org.bukkit.util.EulerAngle; import org.bukkit.util.Vector; +import org.spacehq.opennbt.tag.builtin.CompoundTag; import us.myles.ViaVersion2.api.item.Item; import us.myles.ViaVersion2.api.type.types.*; import us.myles.ViaVersion2.api.type.types.minecraft.*; @@ -57,7 +58,9 @@ public abstract class Type implements ByteBufReader, ByteBufWriter { public static final Type POSITION = new PositionType(); public static final Type ROTATION = new EulerAngleType(); public static final Type VECTOR = new VectorType(); - public static final Type ITEM = new ItemType(); // TODO + public static final Type NBT = new NBTType(); + + public static final Type ITEM = new ItemType(); public static final Type ITEM_ARRAY = new ItemArrayType(); /* Actual Class */ diff --git a/src/main/java/us/myles/ViaVersion2/api/type/types/ArrayType.java b/src/main/java/us/myles/ViaVersion2/api/type/types/ArrayType.java index 169dba013..e27eb92a8 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/types/ArrayType.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/types/ArrayType.java @@ -12,7 +12,7 @@ public class ArrayType extends Type { } @Override - public T[] read(ByteBuf buffer) { + public T[] read(ByteBuf buffer) throws Exception{ int amount = Type.VAR_INT.read(buffer); Object[] array = new Object[amount]; for (int i = 0; i < amount; i++) { @@ -22,7 +22,7 @@ public class ArrayType extends Type { } @Override - public void write(ByteBuf buffer, T[] object) { + public void write(ByteBuf buffer, T[] object) throws Exception{ Type.VAR_INT.write(buffer, object.length); for (T o : object) { elementType.write(buffer, o); diff --git a/src/main/java/us/myles/ViaVersion2/api/type/types/StringType.java b/src/main/java/us/myles/ViaVersion2/api/type/types/StringType.java index 7476feb43..a4eede755 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/types/StringType.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/types/StringType.java @@ -11,7 +11,7 @@ public class StringType extends Type { } @Override - public String read(ByteBuf buffer) { + public String read(ByteBuf buffer) throws Exception { int len = Type.VAR_INT.read(buffer); Preconditions.checkArgument(len <= Short.MAX_VALUE, "Cannot receive string longer than Short.MAX_VALUE (got %s characters)", len); @@ -22,7 +22,7 @@ public class StringType extends Type { } @Override - public void write(ByteBuf buffer, String object) { + public void write(ByteBuf buffer, String object) throws Exception { Preconditions.checkArgument(object.length() <= Short.MAX_VALUE, "Cannot send string longer than Short.MAX_VALUE (got %s characters)", object.length()); byte[] b = object.getBytes(Charsets.UTF_8); diff --git a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/EulerAngleType.java b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/EulerAngleType.java index f0e44dfc4..566931fe6 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/EulerAngleType.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/EulerAngleType.java @@ -11,7 +11,7 @@ public class EulerAngleType extends Type { } @Override - public EulerAngle read(ByteBuf buffer) { + public EulerAngle read(ByteBuf buffer) throws Exception { float x = Type.FLOAT.read(buffer); float y = Type.FLOAT.read(buffer); float z = Type.FLOAT.read(buffer); @@ -20,7 +20,7 @@ public class EulerAngleType extends Type { } @Override - public void write(ByteBuf buffer, EulerAngle object) { + public void write(ByteBuf buffer, EulerAngle object) throws Exception { Type.FLOAT.write(buffer, (float) object.getX()); Type.FLOAT.write(buffer, (float) object.getY()); Type.FLOAT.write(buffer, (float) object.getZ()); diff --git a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemArrayType.java b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemArrayType.java index 86d552df5..0ef8f1e27 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemArrayType.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemArrayType.java @@ -11,7 +11,7 @@ public class ItemArrayType extends Type { } @Override - public Item[] read(ByteBuf buffer) { + public Item[] read(ByteBuf buffer) throws Exception { int amount = Type.SHORT.read(buffer); Item[] array = new Item[amount]; for (int i = 0; i < amount; i++) { @@ -21,7 +21,7 @@ public class ItemArrayType extends Type { } @Override - public void write(ByteBuf buffer, Item[] object) { + public void write(ByteBuf buffer, Item[] object) throws Exception { Type.VAR_INT.write(buffer, object.length); for (Item o : object) { Type.ITEM.write(buffer, o); diff --git a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemType.java b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemType.java index 0c33ecf2e..402766e7a 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemType.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/ItemType.java @@ -4,19 +4,35 @@ import io.netty.buffer.ByteBuf; import us.myles.ViaVersion2.api.item.Item; import us.myles.ViaVersion2.api.type.Type; -// TODO: Implement this class public class ItemType extends Type { public ItemType() { super(Item.class); } @Override - public Item read(ByteBuf buffer) { - return null; + public Item read(ByteBuf buffer) throws Exception { + short id = buffer.readShort(); + if (id < 0) { + return null; + } else { + Item item = new Item(); + item.setId(id); + item.setAmount(buffer.readByte()); + item.setData(buffer.readShort()); + item.setTag(Type.NBT.read(buffer)); + return item; + } } @Override - public void write(ByteBuf buffer, Item object) { - + public void write(ByteBuf buffer, Item object) throws Exception { + if (object == null) { + buffer.writeShort(-1); + } else { + buffer.writeShort(object.getId()); + buffer.writeByte(object.getAmount()); + buffer.writeShort(object.getData()); + Type.NBT.write(buffer, object.getTag()); + } } } diff --git a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/NBTType.java b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/NBTType.java new file mode 100644 index 000000000..c7067aa58 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/NBTType.java @@ -0,0 +1,52 @@ +package us.myles.ViaVersion2.api.type.types.minecraft; + +import com.google.common.base.Preconditions; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import org.spacehq.opennbt.NBTIO; +import org.spacehq.opennbt.tag.builtin.CompoundTag; +import us.myles.ViaVersion2.api.type.Type; + +import java.io.DataInputStream; +import java.io.DataOutputStream; + +public class NBTType extends Type { + public NBTType() { + super(CompoundTag.class); + } + + @Override + public CompoundTag read(ByteBuf buffer) throws Exception { + Preconditions.checkArgument(buffer.readableBytes() <= 2097152, "Cannot read NBT (got %s bytes)", buffer.readableBytes()); + + int readerIndex = buffer.readerIndex(); + byte b = buffer.readByte(); + if (b == 0) { + return null; + } else { + buffer.readerIndex(readerIndex); + ByteBufInputStream bytebufStream = new ByteBufInputStream(buffer); + DataInputStream dataInputStream = new DataInputStream(bytebufStream); + try { + return (CompoundTag) NBTIO.readTag(dataInputStream); + } finally { + dataInputStream.close(); + } + } + } + + @Override + public void write(ByteBuf buffer, CompoundTag object) throws Exception { + if (object == null) { + buffer.writeByte(0); + } else { + ByteBufOutputStream bytebufStream = new ByteBufOutputStream(buffer); + DataOutputStream dataOutputStream = new DataOutputStream(bytebufStream); + + NBTIO.writeTag(dataOutputStream, object); + + dataOutputStream.close(); + } + } +} diff --git a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/VectorType.java b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/VectorType.java index fde8a2dbc..bdb5716e7 100644 --- a/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/VectorType.java +++ b/src/main/java/us/myles/ViaVersion2/api/type/types/minecraft/VectorType.java @@ -10,7 +10,7 @@ public class VectorType extends Type { } @Override - public Vector read(ByteBuf buffer) { + public Vector read(ByteBuf buffer) throws Exception { int x = Type.INT.read(buffer); int y = Type.INT.read(buffer); int z = Type.INT.read(buffer); @@ -19,7 +19,7 @@ public class VectorType extends Type { } @Override - public void write(ByteBuf buffer, Vector object) { + public void write(ByteBuf buffer, Vector object) throws Exception { Type.INT.write(buffer, object.getBlockX()); Type.INT.write(buffer, object.getBlockY()); Type.INT.write(buffer, object.getBlockZ());