From a12ac37cc3d17efc3e4ce78d7fc152c8abd29897 Mon Sep 17 00:00:00 2001 From: Thinkofname Date: Tue, 10 May 2016 21:48:01 +1000 Subject: [PATCH] Support Minecraft 1.9.4 and tidy up packet handling --- .../net/md_5/bungee/protocol/Protocol.java | 317 ++++++++++++------ .../bungee/protocol/ProtocolConstants.java | 7 + .../main/java/net/md_5/bungee/BungeeCord.java | 6 +- .../bungee/connection/InitialHandler.java | 9 +- .../net/md_5/bungee/entitymap/EntityMap.java | 2 + .../bungee/entitymap/EntityMap_1_9_4.java | 174 ++++++++++ 6 files changed, 402 insertions(+), 113 deletions(-) create mode 100644 proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_9_4.java diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java index 907a73ff..2378754e 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java @@ -1,10 +1,8 @@ package net.md_5.bungee.protocol; import com.google.common.base.Preconditions; -import gnu.trove.map.TIntIntMap; import gnu.trove.map.TIntObjectMap; import gnu.trove.map.TObjectIntMap; -import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.map.hash.TObjectIntHashMap; import java.lang.reflect.Constructor; @@ -47,7 +45,10 @@ public enum Protocol { { - TO_SERVER.registerPacket( 0x00, Handshake.class ); + TO_SERVER.registerPacket( + Handshake.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x00 ) + ); } }, // 0 @@ -55,27 +56,106 @@ public enum Protocol { { - TO_CLIENT.registerPacket( 0x00, 0x1F, KeepAlive.class ); - TO_CLIENT.registerPacket( 0x01, 0x23, Login.class ); - TO_CLIENT.registerPacket( 0x02, 0x0F, Chat.class ); - TO_CLIENT.registerPacket( 0x07, 0x33, Respawn.class ); - TO_CLIENT.registerPacket( 0x0C, 0x0C, BossBar.class, true ); - TO_CLIENT.registerPacket( 0x38, 0x2D, PlayerListItem.class ); // PlayerInfo - TO_CLIENT.registerPacket( 0x3A, 0x0E, TabCompleteResponse.class ); - TO_CLIENT.registerPacket( 0x3B, 0x3F, ScoreboardObjective.class ); - TO_CLIENT.registerPacket( 0x3C, 0x42, ScoreboardScore.class ); - TO_CLIENT.registerPacket( 0x3D, 0x38, ScoreboardDisplay.class ); - TO_CLIENT.registerPacket( 0x3E, 0x41, Team.class ); - TO_CLIENT.registerPacket( 0x3F, 0x18, PluginMessage.class ); - TO_CLIENT.registerPacket( 0x40, 0x1A, Kick.class ); - TO_CLIENT.registerPacket( 0x45, 0x45, Title.class ); - TO_CLIENT.registerPacket( 0x47, 0x48, PlayerListHeaderFooter.class ); + TO_CLIENT.registerPacket( + KeepAlive.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x00 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x1F ) + ); + TO_CLIENT.registerPacket( + Login.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x01 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x23 ) + ); + TO_CLIENT.registerPacket( + Chat.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x02 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x0F ) + ); + TO_CLIENT.registerPacket( + Respawn.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x07 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x33 ) + ); + TO_CLIENT.registerPacket( + BossBar.class, + map( ProtocolConstants.MINECRAFT_1_9, 0x0C ) + ); + TO_CLIENT.registerPacket( + PlayerListItem.class, // PlayerInfo + map( ProtocolConstants.MINECRAFT_1_8, 0x38 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x2D ) + ); + TO_CLIENT.registerPacket( + TabCompleteResponse.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x3A ), + map( ProtocolConstants.MINECRAFT_1_9, 0x0E ) + ); + TO_CLIENT.registerPacket( + ScoreboardObjective.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x3B ), + map( ProtocolConstants.MINECRAFT_1_9, 0x3F ) + ); + TO_CLIENT.registerPacket( + ScoreboardScore.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x3C ), + map( ProtocolConstants.MINECRAFT_1_9, 0x42 ) + ); + TO_CLIENT.registerPacket( + ScoreboardDisplay.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x3D ), + map( ProtocolConstants.MINECRAFT_1_9, 0x38 ) + ); + TO_CLIENT.registerPacket( + Team.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x3E ), + map( ProtocolConstants.MINECRAFT_1_9, 0x41 ) + ); + TO_CLIENT.registerPacket( + PluginMessage.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x3F ), + map( ProtocolConstants.MINECRAFT_1_9, 0x18 ) + ); + TO_CLIENT.registerPacket( + Kick.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x40 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x1A ) + ); + TO_CLIENT.registerPacket( + Title.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x45 ) + ); + TO_CLIENT.registerPacket( + PlayerListHeaderFooter.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x47 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x48 ), + map(ProtocolConstants.MINECRAFT_1_9_4, 0x47 ) + ); - TO_SERVER.registerPacket( 0x00, 0x0B, KeepAlive.class ); - TO_SERVER.registerPacket( 0x01, 0x02, Chat.class ); - TO_SERVER.registerPacket( 0x14, 0x01, TabCompleteRequest.class ); - TO_SERVER.registerPacket( 0x15, 0x04, ClientSettings.class ); - TO_SERVER.registerPacket( 0x17, 0x09, PluginMessage.class ); + TO_SERVER.registerPacket( + KeepAlive.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x00 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x0B ) + ); + TO_SERVER.registerPacket( + Chat.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x01 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x02 ) + ); + TO_SERVER.registerPacket( + TabCompleteRequest.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x14 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x01 ) + ); + TO_SERVER.registerPacket( + ClientSettings.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x15 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x04 ) + ); + TO_SERVER.registerPacket( + PluginMessage.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x17 ), + map( ProtocolConstants.MINECRAFT_1_9, 0x09 ) + ); } }, // 1 @@ -83,11 +163,23 @@ public enum Protocol { { - TO_CLIENT.registerPacket( 0x00, StatusResponse.class ); - TO_CLIENT.registerPacket( 0x01, PingPacket.class ); + TO_CLIENT.registerPacket( + StatusResponse.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x00 ) + ); + TO_CLIENT.registerPacket( + PingPacket.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x01 ) + ); - TO_SERVER.registerPacket( 0x00, StatusRequest.class ); - TO_SERVER.registerPacket( 0x01, PingPacket.class ); + TO_SERVER.registerPacket( + StatusRequest.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x00 ) + ); + TO_SERVER.registerPacket( + PingPacket.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x01 ) + ); } }, //2 @@ -95,68 +187,95 @@ public enum Protocol { { - TO_CLIENT.registerPacket( 0x00, Kick.class ); - TO_CLIENT.registerPacket( 0x01, EncryptionRequest.class ); - TO_CLIENT.registerPacket( 0x02, LoginSuccess.class ); - TO_CLIENT.registerPacket( 0x03, SetCompression.class ); + TO_CLIENT.registerPacket( + Kick.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x00 ) + ); + TO_CLIENT.registerPacket( + EncryptionRequest.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x01 ) + ); + TO_CLIENT.registerPacket( + LoginSuccess.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x02 ) + ); + TO_CLIENT.registerPacket( + SetCompression.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x03 ) + ); - TO_SERVER.registerPacket( 0x00, LoginRequest.class ); - TO_SERVER.registerPacket( 0x01, EncryptionResponse.class ); + TO_SERVER.registerPacket( + LoginRequest.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x00 ) + ); + TO_SERVER.registerPacket( + EncryptionResponse.class, + map( ProtocolConstants.MINECRAFT_1_8, 0x01 ) + ); } }; /*========================================================================*/ public static final int MAX_PACKET_ID = 0xFF; - public static List supportedVersions = Arrays.asList( - ProtocolConstants.MINECRAFT_1_8, - ProtocolConstants.MINECRAFT_1_9, - ProtocolConstants.MINECRAFT_1_9_1, - ProtocolConstants.MINECRAFT_1_9_2 - ); /*========================================================================*/ public final DirectionData TO_SERVER = new DirectionData( ProtocolConstants.Direction.TO_SERVER ); public final DirectionData TO_CLIENT = new DirectionData( ProtocolConstants.Direction.TO_CLIENT ); @RequiredArgsConstructor - public class DirectionData + private static class ProtocolData { + + private final int protocolVersion; + private final TObjectIntMap> packetMap = new TObjectIntHashMap<>( MAX_PACKET_ID ); + private final TIntObjectMap> packetConstructors = new TIntObjectHashMap<>( MAX_PACKET_ID ); + } + + @RequiredArgsConstructor + private static class ProtocolMapping { + private final int protocolVersion; + private final int packetID; + } + // Helper method + private static ProtocolMapping map(int protocol, int id) { + return new ProtocolMapping(protocol, id); + } + + @RequiredArgsConstructor + public static class DirectionData { + private final TIntObjectMap protocols = new TIntObjectHashMap<>(); + { + for ( int protocol : ProtocolConstants.SUPPORTED_VERSION_IDS ) + { + protocols.put( protocol, new ProtocolData( protocol ) ); + } + } + private final TIntObjectMap> linkedProtocols = new TIntObjectHashMap<>(); + { + linkedProtocols.put( ProtocolConstants.MINECRAFT_1_8, Arrays.asList( + ProtocolConstants.MINECRAFT_1_9 + )); + linkedProtocols.put( ProtocolConstants.MINECRAFT_1_9, Arrays.asList(ProtocolConstants.MINECRAFT_1_9_1, + ProtocolConstants.MINECRAFT_1_9_2, + ProtocolConstants.MINECRAFT_1_9_4 + )); + } + @Getter private final ProtocolConstants.Direction direction; - private final TObjectIntMap> packetMap = new TObjectIntHashMap<>( MAX_PACKET_ID ); - private final Class[] packetClasses = new Class[ MAX_PACKET_ID ]; - private final Constructor[] packetConstructors = new Constructor[ MAX_PACKET_ID ]; - - private final TIntObjectMap packetRemap = new TIntObjectHashMap<>(); - private final TIntObjectMap packetRemapInv = new TIntObjectHashMap<>(); - - { - packetRemap.put( ProtocolConstants.MINECRAFT_1_8, new TIntIntHashMap() ); - packetRemapInv.put( ProtocolConstants.MINECRAFT_1_8, new TIntIntHashMap() ); - packetRemap.put( ProtocolConstants.MINECRAFT_1_9, new TIntIntHashMap() ); - packetRemapInv.put( ProtocolConstants.MINECRAFT_1_9, new TIntIntHashMap() ); - packetRemap.put( ProtocolConstants.MINECRAFT_1_9_1, packetRemap.get( ProtocolConstants.MINECRAFT_1_9 ) ); - packetRemapInv.put( ProtocolConstants.MINECRAFT_1_9_1, packetRemapInv.get( ProtocolConstants.MINECRAFT_1_9 ) ); - packetRemap.put( ProtocolConstants.MINECRAFT_1_9_2, packetRemap.get( ProtocolConstants.MINECRAFT_1_9 ) ); - packetRemapInv.put( ProtocolConstants.MINECRAFT_1_9_2, packetRemapInv.get( ProtocolConstants.MINECRAFT_1_9 ) ); - } public final DefinedPacket createPacket(int id, int protocol) { - TIntIntMap remap = packetRemap.get( protocol ); - if ( remap != null ) + ProtocolData protocolData = protocols.get( protocol ); + if (protocolData == null) { - if ( !remap.containsKey( id ) ) - { - return null; - } - id = remap.get( id ); + throw new BadPacketException( "Unsupported protocol" ); } if ( id > MAX_PACKET_ID ) { throw new BadPacketException( "Packet with id " + id + " outside of range " ); } - Constructor constructor = packetConstructors[id]; + Constructor constructor = protocolData.packetConstructors.get( id ); try { return ( constructor == null ) ? null : constructor.newInstance(); @@ -166,57 +285,51 @@ public enum Protocol } } - protected final void registerPacket(int id, Class packetClass) - { - registerPacket( id, id, packetClass ); - } - - protected final void registerPacket(int id, int newId, Class packetClass) - { - registerPacket( id, newId, packetClass, false ); - - } - - protected final void registerPacket(int id, int newId, Class packetClass, boolean newOnly) + protected final void registerPacket(Class packetClass, ProtocolMapping ...mappings) { try { - packetConstructors[id] = packetClass.getDeclaredConstructor(); + Constructor constructor = packetClass.getDeclaredConstructor(); + for ( ProtocolMapping mapping : mappings ) + { + ProtocolData data = protocols.get( mapping.protocolVersion ); + data.packetMap.put( packetClass, mapping.packetID ); + data.packetConstructors.put( mapping.packetID, constructor ); + + List links = linkedProtocols.get( mapping.protocolVersion ); + if ( links != null ) + { + links: for ( int link : links ) + { + // Check for manual mappings + for ( ProtocolMapping m : mappings ) + { + if ( m == mapping ) continue; + if ( m.protocolVersion == link ) continue links; + List innerLinks = linkedProtocols.get( m.protocolVersion ); + if ( innerLinks != null && innerLinks.contains( link ) ) continue links; + } + registerPacket( packetClass, map( link, mapping.packetID ) ); + } + } + } } catch ( NoSuchMethodException ex ) { throw new BadPacketException( "No NoArgsConstructor for packet class " + packetClass ); } - packetClasses[id] = packetClass; - packetMap.put( packetClass, id ); - - if ( !newOnly ) - { - packetRemap.get( ProtocolConstants.MINECRAFT_1_8 ).put( id, id ); - packetRemapInv.get( ProtocolConstants.MINECRAFT_1_8 ).put( id, id ); - } - - packetRemap.get( ProtocolConstants.MINECRAFT_1_9 ).put( newId, id ); - packetRemapInv.get( ProtocolConstants.MINECRAFT_1_9 ).put( id, newId ); - } - - protected final void unregisterPacket(int id) - { - packetMap.remove( packetClasses[id] ); - packetClasses[id] = null; - packetConstructors[id] = null; } final int getId(Class packet, int protocol) { - Preconditions.checkArgument( packetMap.containsKey( packet ), "Cannot get ID for packet " + packet ); - int id = packetMap.get( packet ); - TIntIntMap remap = packetRemapInv.get( protocol ); - if ( remap != null ) + ProtocolData protocolData = protocols.get( protocol ); + if (protocolData == null) { - return remap.get( id ); + throw new BadPacketException( "Unsupported protocol" ); } - return id; + Preconditions.checkArgument( protocolData.packetMap.containsKey( packet ), "Cannot get ID for packet " + packet ); + + return protocolData.packetMap.get( packet ); } } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java index 4b6d9fa1..2501512e 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java @@ -10,10 +10,17 @@ public class ProtocolConstants public static final int MINECRAFT_1_9 = 107; public static final int MINECRAFT_1_9_1 = 108; public static final int MINECRAFT_1_9_2 = 109; + public static final int MINECRAFT_1_9_4 = 110; public static final List SUPPORTED_VERSIONS = Arrays.asList( "1.8.x", "1.9.x" ); + public static final List SUPPORTED_VERSION_IDS = Arrays.asList(ProtocolConstants.MINECRAFT_1_8, + ProtocolConstants.MINECRAFT_1_9, + ProtocolConstants.MINECRAFT_1_9_1, + ProtocolConstants.MINECRAFT_1_9_2, + ProtocolConstants.MINECRAFT_1_9_4 + ); public enum Direction { diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 1189ac69..ac08d8ee 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -15,7 +15,6 @@ import net.md_5.bungee.api.chat.TranslatableComponent; import net.md_5.bungee.chat.TextComponentSerializer; import net.md_5.bungee.chat.TranslatableComponentSerializer; import net.md_5.bungee.module.ModuleManager; -import com.google.common.io.ByteStreams; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.chat.ComponentSerializer; @@ -58,9 +57,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; -import jline.UnsupportedTerminal; import jline.console.ConsoleReader; -import jline.internal.Log; import lombok.Getter; import lombok.Setter; import lombok.Synchronized; @@ -80,7 +77,6 @@ import net.md_5.bungee.forge.ForgeConstants; import net.md_5.bungee.log.LoggingOutputStream; import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.protocol.DefinedPacket; -import net.md_5.bungee.protocol.Protocol; import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.Chat; import net.md_5.bungee.protocol.packet.PluginMessage; @@ -590,7 +586,7 @@ public class BungeeCord extends ProxyServer @Override public int getProtocolVersion() { - return Protocol.supportedVersions.get( Protocol.supportedVersions.size() - 1 ); + return ProtocolConstants.SUPPORTED_VERSION_IDS.get( ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1 ); } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index 729aeafb..d714836c 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -6,12 +6,10 @@ import java.math.BigInteger; import java.net.InetSocketAddress; import java.net.URLEncoder; import java.security.MessageDigest; -import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.logging.Level; import javax.crypto.SecretKey; - import com.google.gson.Gson; import java.util.concurrent.TimeUnit; import lombok.Getter; @@ -20,7 +18,6 @@ import net.md_5.bungee.*; import net.md_5.bungee.api.Callback; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.Favicon; -import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; @@ -41,6 +38,7 @@ import net.md_5.bungee.netty.cipher.CipherDecoder; import net.md_5.bungee.netty.cipher.CipherEncoder; import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.PacketWrapper; +import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.Handshake; import net.md_5.bungee.protocol.packet.PluginMessage; import net.md_5.bungee.protocol.packet.EncryptionResponse; @@ -51,7 +49,6 @@ import net.md_5.bungee.api.event.PlayerHandshakeEvent; import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.jni.cipher.BungeeCipher; import net.md_5.bungee.protocol.Protocol; -import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.LegacyHandshake; import net.md_5.bungee.protocol.packet.LegacyPing; import net.md_5.bungee.protocol.packet.LoginRequest; @@ -235,7 +232,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection ( (BungeeServerInfo) forced ).ping( pingBack, handshake.getProtocolVersion() ); } else { - int protocol = ( Protocol.supportedVersions.contains( handshake.getProtocolVersion() ) ) ? handshake.getProtocolVersion() : bungee.getProtocolVersion(); + int protocol = ( ProtocolConstants.SUPPORTED_VERSION_IDS.contains( handshake.getProtocolVersion() ) ) ? handshake.getProtocolVersion() : bungee.getProtocolVersion(); pingBack.done( new ServerPing( new ServerPing.Protocol( bungee.getName() + " " + bungee.getGameVersion(), protocol ), new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ), @@ -312,7 +309,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection Preconditions.checkState( thisState == State.USERNAME, "Not expecting USERNAME" ); this.loginRequest = loginRequest; - if ( !Protocol.supportedVersions.contains( handshake.getProtocolVersion() ) ) + if ( !ProtocolConstants.SUPPORTED_VERSION_IDS.contains( handshake.getProtocolVersion() ) ) { disconnect( bungee.getTranslation( "outdated_server" ) ); return; 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 index d9286535..02881ac6 100644 --- a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java @@ -31,6 +31,8 @@ public abstract class EntityMap case ProtocolConstants.MINECRAFT_1_9_1: case ProtocolConstants.MINECRAFT_1_9_2: return EntityMap_1_9.INSTANCE; + case ProtocolConstants.MINECRAFT_1_9_4: + return EntityMap_1_9_4.INSTANCE; } throw new RuntimeException( "Version " + version + " has no entity map" ); } diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_9_4.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_9_4.java new file mode 100644 index 00000000..c7442bea --- /dev/null +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_9_4.java @@ -0,0 +1,174 @@ +package net.md_5.bungee.entitymap; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.netty.buffer.ByteBuf; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.UserConnection; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.ProtocolConstants; + +import java.util.UUID; + +class EntityMap_1_9_4 extends EntityMap +{ + + static final EntityMap_1_9_4 INSTANCE = new EntityMap_1_9_4(); + + EntityMap_1_9_4() + { + addRewrite( 0x00, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Object : PacketPlayOutSpawnEntity + addRewrite( 0x01, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Experience Orb : PacketPlayOutSpawnEntityExperienceOrb + addRewrite( 0x03, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Mob : PacketPlayOutSpawnEntityLiving + addRewrite( 0x04, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Painting : PacketPlayOutSpawnEntityPainting + addRewrite( 0x05, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Player : PacketPlayOutNamedEntitySpawn + addRewrite( 0x06, ProtocolConstants.Direction.TO_CLIENT, true ); // Animation : PacketPlayOutAnimation + addRewrite( 0x08, ProtocolConstants.Direction.TO_CLIENT, true ); // Block Break Animation : PacketPlayOutBlockBreakAnimation + addRewrite( 0x1B, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Status : PacketPlayOutEntityStatus + addRewrite( 0x25, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Relative Move : PacketPlayOutRelEntityMove + addRewrite( 0x26, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Look and Relative Move : PacketPlayOutRelEntityMoveLook + addRewrite( 0x27, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Look : PacketPlayOutEntityLook + addRewrite( 0x28, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity : PacketPlayOutEntity + addRewrite( 0x2F, ProtocolConstants.Direction.TO_CLIENT, true ); // Use bed : PacketPlayOutBed + addRewrite( 0x31, ProtocolConstants.Direction.TO_CLIENT, true ); // Remove Entity Effect : PacketPlayOutRemoveEntityEffect + addRewrite( 0x34, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Head Look : PacketPlayOutEntityHeadRotation + addRewrite( 0x36, ProtocolConstants.Direction.TO_CLIENT, true ); // Camera : PacketPlayOutCamera + addRewrite( 0x39, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Metadata : PacketPlayOutEntityMetadata + addRewrite( 0x3B, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Velocity : PacketPlayOutEntityVelocity + addRewrite( 0x3C, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Equipment : PacketPlayOutEntityEquipment + addRewrite( 0x40, ProtocolConstants.Direction.TO_CLIENT, true ); // Attach Entity : PacketPlayOutMount + addRewrite( 0x48, ProtocolConstants.Direction.TO_CLIENT, true ); // Collect Item : PacketPlayOutCollect + addRewrite( 0x49, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Teleport : PacketPlayOutEntityTeleport + addRewrite( 0x4A, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Properties : PacketPlayOutUpdateAttributes + addRewrite( 0x4B, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Effect : PacketPlayOutEntityEffect + + addRewrite( 0x0A, ProtocolConstants.Direction.TO_SERVER, true ); // Use Entity : PacketPlayInUseEntity + addRewrite( 0x14, ProtocolConstants.Direction.TO_SERVER, true ); // Entity Action : PacketPlayInEntityAction + } + + @Override + @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE") + 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; + int jumpIndex = packet.readerIndex(); + switch ( packetId ) + { + case 0x48 /* Collect Item : PacketPlayOutCollect */: + DefinedPacket.readVarInt( packet ); + rewriteVarInt( packet, oldId, newId, packet.readerIndex() ); + break; + case 0x40 /* Attach Entity : PacketPlayOutMount */: + DefinedPacket.readVarInt( packet ); + jumpIndex = packet.readerIndex(); + // Fall through on purpose to int array of IDs + case 0x30 /* Destroy Entities : PacketPlayOutEntityDestroy */: + int count = DefinedPacket.readVarInt( packet ); + int[] ids = new int[ count ]; + for ( int i = 0; i < count; i++ ) + { + ids[i] = DefinedPacket.readVarInt( packet ); + } + packet.readerIndex( jumpIndex ); + packet.writerIndex( jumpIndex ); + DefinedPacket.writeVarInt( count, packet ); + for ( int id : ids ) + { + if ( id == oldId ) + { + id = newId; + } else if ( id == newId ) + { + id = oldId; + } + DefinedPacket.writeVarInt( id, packet ); + } + break; + case 0x00 /* Spawn Object : PacketPlayOutSpawnEntity */: + DefinedPacket.readVarInt( packet ); + DefinedPacket.readUUID( packet ); + int type = packet.readUnsignedByte(); + + if ( type == 60 || type == 90 || type == 91 ) + { + if ( type == 60 || type == 91 ) + { + oldId = oldId + 1; + newId = newId + 1; + } + + packet.skipBytes( 26 ); // double, double, double, byte, byte + int position = packet.readerIndex(); + int readId = packet.readInt(); + if ( readId == oldId ) + { + packet.setInt( position, newId ); + } else if ( readId == newId ) + { + packet.setInt( position, oldId ); + } + } + break; + case 0x05 /* Spawn Player : PacketPlayOutNamedEntitySpawn */: + DefinedPacket.readVarInt( packet ); // Entity ID + int idLength = packet.readerIndex() - readerIndex - packetIdLength; + UUID uuid = DefinedPacket.readUUID( packet ); + ProxiedPlayer player; + if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) + { + int previous = packet.writerIndex(); + packet.readerIndex( readerIndex ); + packet.writerIndex( readerIndex + packetIdLength + idLength ); + DefinedPacket.writeUUID( player.getUniqueId(), packet ); + packet.writerIndex( previous ); + } + break; + case 0x2C /* Combat Event : PacketPlayOutCombatEvent */: + int event = packet.readUnsignedByte(); + if ( event == 1 /* End Combat*/ ) + { + DefinedPacket.readVarInt( packet ); + rewriteInt( packet, oldId, newId, packet.readerIndex() ); + } else if ( event == 2 /* Entity Dead */ ) + { + int position = packet.readerIndex(); + rewriteVarInt( packet, oldId, newId, packet.readerIndex() ); + packet.readerIndex( position ); + DefinedPacket.readVarInt( packet ); + rewriteInt( packet, oldId, newId, packet.readerIndex() ); + } + break; + } + packet.readerIndex( readerIndex ); + } + + @Override + public void rewriteServerbound(ByteBuf packet, int oldId, int newId) + { + super.rewriteServerbound( packet, oldId, newId ); + // Special cases + int readerIndex = packet.readerIndex(); + int packetId = DefinedPacket.readVarInt( packet ); + int packetIdLength = packet.readerIndex() - readerIndex; + + if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) + { + UUID uuid = DefinedPacket.readUUID( packet ); + ProxiedPlayer player; + if ( ( player = BungeeCord.getInstance().getPlayer( uuid ) ) != null ) + { + int previous = packet.writerIndex(); + packet.readerIndex( readerIndex ); + packet.writerIndex( readerIndex + packetIdLength ); + DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); + packet.writerIndex( previous ); + } + } + packet.readerIndex( readerIndex ); + } +}