Split up EntityMap into different protocol versions

This commit is contained in:
Thinkofdeath 2014-04-16 11:05:44 +01:00
parent 5a638f2290
commit ca7c755ecd
7 changed files with 272 additions and 220 deletions

View File

@ -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 );
}
}

View File

@ -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.api.tab.TabListHandler;
import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.chat.ComponentSerializer;
import net.md_5.bungee.connection.InitialHandler; 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.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss; import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.protocol.PacketWrapper; import net.md_5.bungee.protocol.PacketWrapper;
@ -116,7 +117,7 @@ public final class UserConnection implements ProxiedPlayer
public void init() public void init()
{ {
this.entityRewrite = new EntityMap( getPendingConnection().getVersion() ); this.entityRewrite = EntityMap.getEntityMap( getPendingConnection().getVersion() );
this.displayName = name; this.displayName = name;
try try

View File

@ -5,7 +5,6 @@ import com.google.common.io.ByteStreams;
import java.io.DataInput; import java.io.DataInput;
import java.util.Objects; import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.md_5.bungee.EntityMap;
import net.md_5.bungee.ServerConnection; import net.md_5.bungee.ServerConnection;
import net.md_5.bungee.api.event.ServerDisconnectEvent; import net.md_5.bungee.api.event.ServerDisconnectEvent;
import net.md_5.bungee.UserConnection; import net.md_5.bungee.UserConnection;

View File

@ -2,7 +2,6 @@ package net.md_5.bungee.connection;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import net.md_5.bungee.BungeeCord; import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.EntityMap;
import net.md_5.bungee.UserConnection; import net.md_5.bungee.UserConnection;
import net.md_5.bungee.Util; import net.md_5.bungee.Util;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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 );
}
}