From aeec7e5f952f9d0a357dec543f38960b9ea2763c Mon Sep 17 00:00:00 2001 From: Matsv Date: Thu, 29 Sep 2016 16:33:14 +0200 Subject: [PATCH] Start working on packet-level chunk bulks --- .../BukkitViaBulkChunkTranslator.java | 7 +- .../myles/ViaVersion/api/PacketWrapper.java | 2 +- .../api/protocol/ProtocolRegistry.java | 6 +- .../api/type/types/CustomByteType.java | 26 +++++++ .../packets/WorldPackets.java | 36 +++++++--- .../BulkChunkTranslatorProvider.java | 72 ++++++++++++++++++- .../storage/ClientChunks.java | 4 +- .../us/myles/ViaVersion/util/GsonUtil.java | 2 - .../SpongeViaBulkChunkTranslator.java | 5 ++ 9 files changed, 136 insertions(+), 24 deletions(-) create mode 100644 common/src/main/java/us/myles/ViaVersion/api/type/types/CustomByteType.java diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/providers/BukkitViaBulkChunkTranslator.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/providers/BukkitViaBulkChunkTranslator.java index 25d8370b5..fd4a3a271 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/providers/BukkitViaBulkChunkTranslator.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/providers/BukkitViaBulkChunkTranslator.java @@ -3,9 +3,9 @@ package us.myles.ViaVersion.bukkit.providers; import com.google.common.collect.Lists; import us.myles.ViaVersion.ViaVersionPlugin; import us.myles.ViaVersion.api.Via; +import us.myles.ViaVersion.bukkit.util.NMSUtil; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks; -import us.myles.ViaVersion.bukkit.util.NMSUtil; import us.myles.ViaVersion.util.ReflectionUtil; import java.lang.reflect.Method; @@ -79,4 +79,9 @@ public class BukkitViaBulkChunkTranslator extends BulkChunkTranslatorProvider { public boolean isFiltered(Class packetClass) { return packetClass.getName().endsWith("PacketPlayOutMapChunkBulk"); } + + @Override + public boolean isPacketLevel() { + return false; + } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/PacketWrapper.java b/common/src/main/java/us/myles/ViaVersion/api/PacketWrapper.java index 0f4d4307a..7c3441825 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/PacketWrapper.java +++ b/common/src/main/java/us/myles/ViaVersion/api/PacketWrapper.java @@ -358,7 +358,7 @@ public class PacketWrapper { * Be careful not to send packets twice. * (Sends it after current) *
- * This method is no longer used, it's favoured to use send(Protocol) as it will handle the pipeline properly. + * This method is no longer used, it's favoured to use {@link #send(Class)} as it will handle the pipeline properly. * * @throws Exception if it fails to write */ diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java index b736d88bb..51f32af25 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java +++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java @@ -27,13 +27,13 @@ public class ProtocolRegistry { static { // Base Protocol - registerProtocol(BASE_PROTOCOL, Arrays.asList(), -1); + registerProtocol(BASE_PROTOCOL, Collections.emptyList(), -1); // Register built in protocols registerProtocol(new Protocol1_9TO1_8(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_8.getId()); registerProtocol(new Protocol1_9_1TO1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId()); - registerProtocol(new Protocol1_9_3TO1_9_1_2(), Arrays.asList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_9_2.getId()); + registerProtocol(new Protocol1_9_3TO1_9_1_2(), Collections.singletonList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_9_2.getId()); // Only supported for 1.9.4 server to 1.9 (nothing else) - registerProtocol(new Protocol1_9TO1_9_1(), Arrays.asList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_9_2.getId()); + registerProtocol(new Protocol1_9TO1_9_1(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_9_2.getId()); registerProtocol(new Protocol1_9_1_2TO1_9_3_4(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9_3.getId()); registerProtocol(new Protocol1_10To1_9_3_4(), Collections.singletonList(ProtocolVersion.v1_10.getId()), ProtocolVersion.v1_9_3.getId()); diff --git a/common/src/main/java/us/myles/ViaVersion/api/type/types/CustomByteType.java b/common/src/main/java/us/myles/ViaVersion/api/type/types/CustomByteType.java new file mode 100644 index 000000000..097209490 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/CustomByteType.java @@ -0,0 +1,26 @@ +package us.myles.ViaVersion.api.type.types; + +import io.netty.buffer.ByteBuf; +import us.myles.ViaVersion.api.type.PartialType; + +public class CustomByteType extends PartialType { + + public CustomByteType(Integer param) { + super(param, byte[].class); + } + + @Override + public byte[] read(ByteBuf byteBuf, Integer integer) throws Exception { + if (byteBuf.readableBytes() < integer) throw new RuntimeException("Readable bytes does not match expected!"); + + byte[] byteArray = new byte[integer]; + byteBuf.readBytes(byteArray); + + return byteArray; + } + + @Override + public void write(ByteBuf byteBuf, Integer integer, byte[] bytes) throws Exception { + byteBuf.writeBytes(bytes); + } +} \ No newline at end of file diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java index 8139ce841..2b7301ce1 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java @@ -1,5 +1,7 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.packets; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import org.spacehq.opennbt.tag.builtin.CompoundTag; import org.spacehq.opennbt.tag.builtin.StringTag; import us.myles.ViaVersion.api.PacketWrapper; @@ -15,6 +17,7 @@ import us.myles.ViaVersion.packets.State; import us.myles.ViaVersion.protocols.protocol1_9to1_8.ItemRewriter; import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8; import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.Chunk1_9to1_8; +import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.Effect; import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.SoundEffect; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks; @@ -22,6 +25,9 @@ import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.PlaceBlockTracker; import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.ChunkType; +import java.io.IOException; +import java.util.List; + public class WorldPackets { public static void register(Protocol protocol) { // Sign Update Packet @@ -132,18 +138,26 @@ public class WorldPackets { handler(new PacketHandler() { @Override public void handle(PacketWrapper wrapper) throws Exception { -// ClientChunks clientChunks = wrapper.user().get(ClientChunks.class); -// Chunk1_9to1_8 chunk = (Chunk1_9to1_8) wrapper.passthrough(new ChunkType(clientChunks)); -// if (chunk.isUnloadPacket()) -// wrapper.setId(0x1D); -// -// // eat any other data (Usually happens with unload packets) -// wrapper.read(Type.REMAINING_BYTES); - // TODO: Implement Bulk Chunks - // Boolean - // Column Count + wrapper.cancel(); // Cancel the packet from being sent + BulkChunkTranslatorProvider provider = Via.getManager().getProviders().get(BulkChunkTranslatorProvider.class); - wrapper.cancel(); + // Don't read the packet + if (!provider.isPacketLevel()) + return; + + List list = provider.transformMapChunkBulk(wrapper, wrapper.user().get(ClientChunks.class)); + for (Object obj : list) { + if (!(obj instanceof PacketWrapper)) + throw new IOException("transformMapChunkBulk returned the wrong object type"); + + PacketWrapper output = (PacketWrapper) obj; + + ByteBuf buffer = Unpooled.buffer(); + output.writeToBuffer(buffer); + + PacketWrapper chunkPacket = new PacketWrapper(0x21, buffer, wrapper.user()); + chunkPacket.send(Protocol1_9TO1_8.class, false); + } } }); } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java index 8a4ff5647..dc98c66de 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java @@ -1,9 +1,13 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.providers; +import lombok.Data; +import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.platform.providers.Provider; +import us.myles.ViaVersion.api.type.Type; +import us.myles.ViaVersion.api.type.types.CustomByteType; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; public class BulkChunkTranslatorProvider implements Provider { @@ -14,10 +18,42 @@ public class BulkChunkTranslatorProvider implements Provider { * @param clientChunks The ClientChunks object for the current player * @return A List of all the output packets */ - public List transformMapChunkBulk(Object packet, ClientChunks clientChunks) { - return Arrays.asList(packet); + public List transformMapChunkBulk(Object packet, ClientChunks clientChunks) throws Exception { + if (!(packet instanceof PacketWrapper)) + throw new IllegalArgumentException("The default packet has to be a PacketWrapper for transformMapChunkBulk, unexpected " + packet.getClass()); + + List packets = new ArrayList<>(); + PacketWrapper wrapper = (PacketWrapper) packet; + + boolean skyLight = wrapper.read(Type.BOOLEAN); + int count = wrapper.read(Type.VAR_INT); + + ChunkBulkSection[] metas = new ChunkBulkSection[count]; + for (int i = 0; i < count; i++) { + metas[i] = ChunkBulkSection.read(wrapper, skyLight); + } + + for (ChunkBulkSection meta : metas) { + CustomByteType customByteType = new CustomByteType(meta.getLength()); + meta.setData(wrapper.read(customByteType)); + + // Construct chunk packet + PacketWrapper chunkPacket = new PacketWrapper(0x21, null, wrapper.user()); + chunkPacket.write(Type.INT, meta.getX()); + chunkPacket.write(Type.INT, meta.getZ()); + chunkPacket.write(Type.BOOLEAN, true); // Always ground-up + chunkPacket.write(Type.UNSIGNED_SHORT, meta.getBitMask() & 0x0F); + chunkPacket.write(Type.VAR_INT, meta.getLength()); + chunkPacket.write(customByteType, meta.getData()); + + clientChunks.getBulkChunks().add(ClientChunks.toLong(meta.getX(), meta.getZ())); // Store for later + packets.add(chunkPacket); + } + + return packets; } + /** * Check if a packet of a class should be filtered * @@ -27,4 +63,34 @@ public class BulkChunkTranslatorProvider implements Provider { public boolean isFiltered(Class packet) { return false; } + + /** + * Check if the packet should be provided as PacketWrapper + * + * @return True if enabled + */ + public boolean isPacketLevel() { + return true; + } + + @Data + private static class ChunkBulkSection { + private int x; + private int z; + private int bitMask; + private int length; + private byte[] data; + + public static ChunkBulkSection read(PacketWrapper wrapper, boolean skylight) throws Exception { + ChunkBulkSection bulkSection = new ChunkBulkSection(); + bulkSection.setX(wrapper.read(Type.INT)); + bulkSection.setZ(wrapper.read(Type.INT)); + bulkSection.setBitMask(wrapper.read(Type.UNSIGNED_SHORT)); + + int bitCount = Integer.bitCount(bulkSection.getBitMask()); + bulkSection.setLength((bitCount * ((4096 * 2) + 2048)) + (skylight ? bitCount * 2048 : 0) + 256); // Thanks MCProtocolLib + + return bulkSection; + } + } } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/ClientChunks.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/ClientChunks.java index 67c7fe36d..e4149ef73 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/ClientChunks.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/ClientChunks.java @@ -12,8 +12,6 @@ import java.util.Set; @Getter public class ClientChunks extends StoredObject { - - private final Set loadedChunks = Sets.newConcurrentHashSet(); private final Set bulkChunks = Sets.newConcurrentHashSet(); @@ -25,7 +23,7 @@ public class ClientChunks extends StoredObject { return ((long) msw << 32) + lsw - -2147483648L; } - public List transformMapChunkBulk(Object packet) { + public List transformMapChunkBulk(Object packet) throws Exception { return Via.getManager().getProviders().get(BulkChunkTranslatorProvider.class).transformMapChunkBulk(packet, this); } } diff --git a/common/src/main/java/us/myles/ViaVersion/util/GsonUtil.java b/common/src/main/java/us/myles/ViaVersion/util/GsonUtil.java index b60c6f9e0..38af3892e 100644 --- a/common/src/main/java/us/myles/ViaVersion/util/GsonUtil.java +++ b/common/src/main/java/us/myles/ViaVersion/util/GsonUtil.java @@ -2,11 +2,9 @@ package us.myles.ViaVersion.util; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import lombok.Getter; import lombok.experimental.UtilityClass; @UtilityClass -@Getter public class GsonUtil { private final Gson gson = getGsonBuilder().create(); diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/providers/SpongeViaBulkChunkTranslator.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/providers/SpongeViaBulkChunkTranslator.java index 052fa2bd9..04bc61172 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/providers/SpongeViaBulkChunkTranslator.java +++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/providers/SpongeViaBulkChunkTranslator.java @@ -55,4 +55,9 @@ public class SpongeViaBulkChunkTranslator extends BulkChunkTranslatorProvider { public boolean isFiltered(Class packetClass) { return packetClass.getName().endsWith("S26PacketMapChunkBulk"); } + + @Override + public boolean isPacketLevel() { + return false; + } }