diff --git a/proxy/src/main/java/net/md_5/bungee/EntityMap.java b/proxy/src/main/java/net/md_5/bungee/EntityMap.java deleted file mode 100644 index bc1b67ea..00000000 --- a/proxy/src/main/java/net/md_5/bungee/EntityMap.java +++ /dev/null @@ -1,217 +0,0 @@ -package net.md_5.bungee; - -import io.netty.buffer.ByteBuf; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.connection.LoginResult; -import net.md_5.bungee.protocol.DefinedPacket; -import net.md_5.bungee.protocol.ProtocolConstants; -import net.md_5.bungee.protocol.packet.LoginRequest; - -/** - * Class to rewrite integers within packets. - */ -public class EntityMap -{ - - private final boolean[] clientboundInts = new boolean[ 256 ]; - private final boolean[] clientboundVarInts = new boolean[ 256 ]; - - private final boolean[] serverboundInts = new boolean[ 256 ]; - private final boolean[] serverboundVarInts = new boolean[ 256 ]; - - private final int version; - - public EntityMap(int version) - { - this.version = version; - - clientboundInts[0x04] = true; // Entity Equipment - clientboundInts[0x0A] = true; // Use bed - clientboundVarInts[0x0B] = true; // Animation - clientboundVarInts[0x0C] = true; // Spawn Player - clientboundInts[0x0D] = true; // Collect Item - clientboundVarInts[0x0E] = true; // Spawn Object - clientboundVarInts[0x0F] = true; // Spawn Mob - clientboundVarInts[0x10] = true; // Spawn Painting - clientboundVarInts[0x11] = true; // Spawn Experience Orb - clientboundInts[0x12] = true; // Entity Velocity - clientboundInts[0x14] = true; // Entity - clientboundInts[0x15] = true; // Entity Relative Move - clientboundInts[0x16] = true; // Entity Look - clientboundInts[0x17] = true; // Entity Look and Relative Move - clientboundInts[0x18] = true; // Entity Teleport - clientboundInts[0x19] = true; // Entity Head Look - clientboundInts[0x1A] = true; // Entity Status - clientboundInts[0x1B] = true; // Attach Entity - clientboundInts[0x1C] = true; // Entity Metadata - clientboundInts[0x1D] = true; // Entity Effect - clientboundInts[0x1E] = true; // Remove Entity Effect - clientboundInts[0x20] = true; // Entity Properties - clientboundVarInts[0x25] = true; // Block Break Animation - clientboundVarInts[0x2C] = true; // Spawn Global Entity - - serverboundInts[0x02] = true; // Use Entity - serverboundInts[0x0A] = true; // Animation - serverboundInts[0x0B] = true; // Entity Action - - if ( version >= ProtocolConstants.MINECRAFT_14_11_a ) - { - migrateIntToVarint( clientboundInts, clientboundVarInts ); - migrateIntToVarint( serverboundInts, serverboundVarInts ); - } - } - - private void migrateIntToVarint(boolean[] ints, boolean[] varints) - { - for ( int i = 0; i < ints.length; i++ ) - { - if ( ints[i] ) - { - varints[i] = true; - ints[i] = false; - } - } - } - - public void rewriteServerbound(ByteBuf packet, int serverEntityId, int clientEntityId) - { - rewrite( packet, serverEntityId, clientEntityId, serverboundInts, serverboundVarInts ); - } - - public void rewriteClientbound(ByteBuf packet, int serverEntityId, int clientEntityId) - { - rewrite( packet, serverEntityId, clientEntityId, clientboundInts, clientboundVarInts ); - - //Special cases - int readerIndex = packet.readerIndex(); - int packetId = DefinedPacket.readVarInt( packet ); - int packetIdLength = packet.readerIndex() - readerIndex; - if ( packetId == 0x0D /* Collect Item */ || packetId == 0x1B /* Attach Entity */ ) - { - int readId = packet.getInt( packetIdLength + 4 ); - if ( readId == serverEntityId ) - { - packet.setInt( packetIdLength + 4, clientEntityId ); - } else if ( readId == clientEntityId ) - { - packet.setInt( packetIdLength + 4, serverEntityId ); - } - } else if ( packetId == 0x13 /* Destroy Entities */ ) - { - int count = packet.getByte( packetIdLength ); - for ( int i = 0; i < count; i++ ) - { - int readId = packet.getInt( packetIdLength + 1 + i * 4 ); - if ( readId == serverEntityId ) - { - packet.setInt( packetIdLength + 1 + i * 4, clientEntityId ); - } else if ( readId == clientEntityId ) - { - packet.setInt( packetIdLength + 1 + i * 4, serverEntityId ); - } - } - } else if ( packetId == 0x0E /* Spawn Object */ ) - { - DefinedPacket.readVarInt( packet ); - int idLength = packet.readerIndex() - readerIndex - packetIdLength; - - int type = packet.getByte( packetIdLength + idLength ); - - if ( type == 60 || type == 90 ) - { - int readId = packet.getInt( packetIdLength + idLength + 15 ); - int newId = -1; - if ( readId == serverEntityId ) - { - packet.setInt( packetIdLength + idLength + 15, clientEntityId ); - newId = clientEntityId; - } else if ( readId == clientEntityId ) - { - packet.setInt( packetIdLength + idLength + 15, serverEntityId ); - newId = clientEntityId; - } - if ( newId != -1 ) - { - if ( newId == 0 && readId != 0 ) - { // Trim off the extra data - packet.readerIndex( readerIndex ); - packet.writerIndex( packet.readableBytes() - 6 ); - } else if ( newId != 0 && readId == 0 ) - { // Add on the extra data - packet.readerIndex( readerIndex ); - packet.capacity( packet.readableBytes() + 6 ); - packet.writerIndex( packet.readableBytes() + 6 ); - } - } - } - } else if ( packetId == 0x0C /* Spawn Player */ && version == ProtocolConstants.MINECRAFT_1_7_6 ) - { - DefinedPacket.readVarInt( packet ); - int idLength = packet.readerIndex() - readerIndex - packetIdLength; - String uuid = DefinedPacket.readString( packet ); - String username = DefinedPacket.readString( packet ); - int props = DefinedPacket.readVarInt( packet ); - if ( props == 0 ) - { - UserConnection player = (UserConnection) BungeeCord.getInstance().getPlayer( username ); - if ( player != null ) - { - LoginResult profile = player.getPendingConnection().getLoginProfile(); - if ( profile != null && profile.getProperties() != null - && profile.getProperties().length >= 1 ) - { - ByteBuf rest = packet.slice().copy(); - packet.readerIndex( readerIndex ); - packet.writerIndex( readerIndex + packetIdLength + idLength ); - DefinedPacket.writeString( player.getUniqueId().toString(), packet ); - DefinedPacket.writeString( username, packet ); - DefinedPacket.writeVarInt( profile.getProperties().length, packet ); - for ( LoginResult.Property property : profile.getProperties() ) - { - DefinedPacket.writeString( property.getName(), packet ); - DefinedPacket.writeString( property.getValue(), packet ); - DefinedPacket.writeString( property.getSignature(), packet ); - } - packet.writeBytes( rest ); - rest.release(); - } - } - } - } - packet.readerIndex( readerIndex ); - } - - private static void rewrite(ByteBuf packet, int serverEntityId, int clientEntityId, boolean[] ints, boolean[] varints) - { - int readerIndex = packet.readerIndex(); - int packetId = DefinedPacket.readVarInt( packet ); - int packetIdLength = packet.readerIndex() - readerIndex; - - if ( ints[packetId] ) - { - int readId = packet.getInt( packetIdLength ); - if ( readId == serverEntityId ) - { - packet.setInt( packetIdLength, clientEntityId ); - } else if ( readId == clientEntityId ) - { - packet.setInt( packetIdLength, serverEntityId ); - } - } else if ( varints[packetId] ) - { - // Need to rewrite the packet because VarInts are variable length - int readId = DefinedPacket.readVarInt( packet ); - int readIdLength = packet.readerIndex() - readerIndex - packetIdLength; - if ( readId == serverEntityId || readId == clientEntityId ) - { - ByteBuf data = packet.slice().copy(); - packet.readerIndex( readerIndex ); - packet.writerIndex( packetIdLength ); - DefinedPacket.writeVarInt( readId == serverEntityId ? clientEntityId : serverEntityId, packet ); - packet.writeBytes( data ); - data.release(); - } - } - packet.readerIndex( readerIndex ); - } -} diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index e0c2d0b1..20518d37 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -32,6 +32,7 @@ import net.md_5.bungee.api.score.Scoreboard; import net.md_5.bungee.api.tab.TabListHandler; import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.connection.InitialHandler; +import net.md_5.bungee.entitymap.EntityMap; import net.md_5.bungee.netty.ChannelWrapper; import net.md_5.bungee.netty.HandlerBoss; import net.md_5.bungee.protocol.PacketWrapper; @@ -116,7 +117,7 @@ public final class UserConnection implements ProxiedPlayer public void init() { - this.entityRewrite = new EntityMap( getPendingConnection().getVersion() ); + this.entityRewrite = EntityMap.getEntityMap( getPendingConnection().getVersion() ); this.displayName = name; try diff --git a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java index 4603d74e..5f59516b 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java @@ -5,7 +5,6 @@ import com.google.common.io.ByteStreams; import java.io.DataInput; import java.util.Objects; import lombok.RequiredArgsConstructor; -import net.md_5.bungee.EntityMap; import net.md_5.bungee.ServerConnection; import net.md_5.bungee.api.event.ServerDisconnectEvent; import net.md_5.bungee.UserConnection; diff --git a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java index 6f721564..9c3dfe66 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java @@ -2,7 +2,6 @@ package net.md_5.bungee.connection; import com.google.common.base.Preconditions; import net.md_5.bungee.BungeeCord; -import net.md_5.bungee.EntityMap; import net.md_5.bungee.UserConnection; import net.md_5.bungee.Util; import net.md_5.bungee.api.ProxyServer; diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java new file mode 100644 index 00000000..465d5054 --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java @@ -0,0 +1,113 @@ +package net.md_5.bungee.entitymap; + +import io.netty.buffer.ByteBuf; +import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.ProtocolConstants; + +/** + * Class to rewrite integers within packets. + */ +public abstract class EntityMap +{ + + private final boolean[] clientboundInts = new boolean[ 256 ]; + private final boolean[] clientboundVarInts = new boolean[ 256 ]; + + private final boolean[] serverboundInts = new boolean[ 256 ]; + private final boolean[] serverboundVarInts = new boolean[ 256 ]; + + EntityMap() + { + } + + // Returns the correct entity map for the protocol version + public static EntityMap getEntityMap(int version) + { + switch ( version ) + { + case 4: + return new EntityMap_1_7_2(); + case 5: + return new EntityMap_1_7_6(); + } + throw new RuntimeException( "Version " + version + " has no entity map" ); + } + + protected void addRewrite(int id, ProtocolConstants.Direction direction, boolean varint) + { + if ( direction == ProtocolConstants.Direction.TO_CLIENT ) + { + if ( varint ) + { + clientboundVarInts[ id ] = true; + } else + { + clientboundInts[ id ] = true; + } + } else + { + if ( varint ) + { + serverboundVarInts[ id ] = true; + } else + { + serverboundInts[ id ] = true; + } + } + } + + public void rewriteServerbound(ByteBuf packet, int oldId, int newId) + { + rewrite( packet, oldId, newId, serverboundInts, serverboundVarInts ); + } + + public void rewriteClientbound(ByteBuf packet, int oldId, int newId) + { + rewrite( packet, oldId, newId, clientboundInts, clientboundVarInts ); + } + + protected static void rewriteInt(ByteBuf packet, int oldId, int newId, int offset) + { + int readId = packet.getInt( offset ); + if ( readId == oldId ) + { + packet.setInt( offset, newId ); + } else if ( readId == newId ) + { + packet.setInt( offset, oldId ); + } + } + + protected static void rewriteVarInt(ByteBuf packet, int oldId, int newId, int offset) + { + // Need to rewrite the packet because VarInts are variable length + int readId = DefinedPacket.readVarInt( packet ); + int readIdLength = packet.readerIndex() - offset; + if ( readId == oldId || readId == newId ) + { + ByteBuf data = packet.slice().copy(); + packet.readerIndex( offset ); + packet.writerIndex( offset ); + DefinedPacket.writeVarInt( readId == oldId ? newId : oldId, packet ); + packet.writeBytes( data ); + data.release(); + } + } + + // Handles simple packets + private static void rewrite(ByteBuf packet, int oldId, int newId, boolean[] ints, boolean[] varints) + { + int readerIndex = packet.readerIndex(); + int packetId = DefinedPacket.readVarInt( packet ); + int packetIdLength = packet.readerIndex() - readerIndex; + + if ( ints[ packetId ] ) + { + rewriteInt( packet, oldId, newId, readerIndex + packetIdLength ); + } else if ( varints[ packetId ] ) + { + rewriteVarInt( packet, oldId, newId, readerIndex + packetIdLength ); + } + packet.readerIndex( readerIndex ); + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_2.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_2.java new file mode 100644 index 00000000..e04e4fd4 --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_2.java @@ -0,0 +1,97 @@ +package net.md_5.bungee.entitymap; + +import io.netty.buffer.ByteBuf; +import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.ProtocolConstants; + +class EntityMap_1_7_2 extends EntityMap +{ + EntityMap_1_7_2() + { + addRewrite( 0x04, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Equipment + addRewrite( 0x0A, ProtocolConstants.Direction.TO_CLIENT, false ); // Use bed + addRewrite( 0x0B, ProtocolConstants.Direction.TO_CLIENT, true ); // Animation + addRewrite( 0x0C, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Player + addRewrite( 0x0D, ProtocolConstants.Direction.TO_CLIENT, false ); // Collect Item + addRewrite( 0x0E, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Object + addRewrite( 0x0F, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Mob + addRewrite( 0x10, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Painting + addRewrite( 0x11, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Experience Orb + addRewrite( 0x12, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Velocity + addRewrite( 0x14, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity + addRewrite( 0x15, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Relative Move + addRewrite( 0x16, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Look + addRewrite( 0x17, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Look and Relative Move + addRewrite( 0x18, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Teleport + addRewrite( 0x19, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Head Look + addRewrite( 0x1A, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Status + addRewrite( 0x1B, ProtocolConstants.Direction.TO_CLIENT, false ); // Attach Entity + addRewrite( 0x1C, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Metadata + addRewrite( 0x1D, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Effect + addRewrite( 0x1E, ProtocolConstants.Direction.TO_CLIENT, false ); // Remove Entity Effect + addRewrite( 0x20, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Properties + addRewrite( 0x25, ProtocolConstants.Direction.TO_CLIENT, true ); // Block Break Animation + addRewrite( 0x2C, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Global Entity + + addRewrite( 0x02, ProtocolConstants.Direction.TO_SERVER, false ); // Use Entity + addRewrite( 0x0A, ProtocolConstants.Direction.TO_SERVER, false ); // Animation + addRewrite( 0x0B, ProtocolConstants.Direction.TO_SERVER, false ); // Entity Action + } + + @Override + public void rewriteClientbound(ByteBuf packet, int oldId, int newId) + { + super.rewriteClientbound( packet, oldId, newId ); + + //Special cases + int readerIndex = packet.readerIndex(); + int packetId = DefinedPacket.readVarInt( packet ); + int packetIdLength = packet.readerIndex() - readerIndex; + if ( packetId == 0x0D /* Collect Item */ || packetId == 0x1B /* Attach Entity */ ) + { + rewriteInt( packet, readerIndex + packetIdLength + 4, oldId, newId ); + } else if ( packetId == 0x13 /* Destroy Entities */ ) + { + int count = packet.getByte( packetIdLength ); + for ( int i = 0; i < count; i++ ) + { + rewriteInt( packet, oldId, newId, packetIdLength + 1 + i * 4 ); + } + } else if ( packetId == 0x0E /* Spawn Object */ ) + { + DefinedPacket.readVarInt( packet ); + int idLength = packet.readerIndex() - readerIndex - packetIdLength; + + int type = packet.getByte( packetIdLength + idLength ); + + if ( type == 60 || type == 90 ) + { + int readId = packet.getInt( packetIdLength + idLength + 15 ); + int changedId = -1; + if ( readId == oldId ) + { + packet.setInt( packetIdLength + idLength + 15, newId ); + changedId = newId; + } else if ( readId == newId ) + { + packet.setInt( packetIdLength + idLength + 15, oldId ); + changedId = newId; + } + if ( changedId != -1 ) + { + if ( changedId == 0 && readId != 0 ) + { // Trim off the extra data + packet.readerIndex( readerIndex ); + packet.writerIndex( packet.readableBytes() - 6 ); + } else if ( changedId != 0 && readId == 0 ) + { // Add on the extra data + packet.readerIndex( readerIndex ); + packet.capacity( packet.readableBytes() + 6 ); + packet.writerIndex( packet.readableBytes() + 6 ); + } + } + } + } + packet.readerIndex( readerIndex ); + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_6.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_6.java new file mode 100644 index 00000000..99b0ea20 --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_7_6.java @@ -0,0 +1,60 @@ +package net.md_5.bungee.entitymap; + +import io.netty.buffer.ByteBuf; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.UserConnection; +import net.md_5.bungee.connection.LoginResult; +import net.md_5.bungee.protocol.DefinedPacket; + +class EntityMap_1_7_6 extends EntityMap_1_7_2 +{ + EntityMap_1_7_6() + { + super(); + } + + @Override + public void rewriteClientbound(ByteBuf packet, int oldId, int newId) + { + super.rewriteClientbound( packet, oldId, newId ); + + int readerIndex = packet.readerIndex(); + int packetId = DefinedPacket.readVarInt( packet ); + int packetIdLength = packet.readerIndex() - readerIndex; + if ( packetId == 0x0C /* Spawn Player */ ) + { + DefinedPacket.readVarInt( packet ); + int idLength = packet.readerIndex() - readerIndex - packetIdLength; + String uuid = DefinedPacket.readString( packet ); + String username = DefinedPacket.readString( packet ); + int props = DefinedPacket.readVarInt( packet ); + if ( props == 0 ) + { + UserConnection player = (UserConnection) BungeeCord.getInstance().getPlayer( username ); + if ( player != null ) + { + LoginResult profile = player.getPendingConnection().getLoginProfile(); + if ( profile != null && profile.getProperties() != null + && profile.getProperties().length >= 1 ) + { + ByteBuf rest = packet.slice().copy(); + packet.readerIndex( readerIndex ); + packet.writerIndex( readerIndex + packetIdLength + idLength ); + DefinedPacket.writeString( player.getUniqueId().toString(), packet ); + DefinedPacket.writeString( username, packet ); + DefinedPacket.writeVarInt( profile.getProperties().length, packet ); + for ( LoginResult.Property property : profile.getProperties() ) + { + DefinedPacket.writeString( property.getName(), packet ); + DefinedPacket.writeString( property.getValue(), packet ); + DefinedPacket.writeString( property.getSignature(), packet ); + } + packet.writeBytes( rest ); + rest.release(); + } + } + } + } + packet.readerIndex( readerIndex ); + } +}