Add support for Minecraft 1.8.x
This commit allows BungeeCord to support Minecraft clients both of versions 1.7.x and of 1.8.x. There should be no breakages to any other support, however following their deprecation and uselessness within 1.8, the Tab list APIs have been removed. Please report any issues to GitHub and be sure to mention client, server and BungeeCord versions. When used with an appropriate server jar (such as multi protocol Spigot), this will allow clients of many versions to concurrently be connected to the same set of servers.
This commit is contained in:
parent
e99bbff22e
commit
26521cf2ff
@ -15,7 +15,6 @@ import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||
import net.md_5.bungee.api.tab.CustomTabList;
|
||||
|
||||
public abstract class ProxyServer
|
||||
{
|
||||
@ -260,14 +259,6 @@ public abstract class ProxyServer
|
||||
*/
|
||||
public abstract void broadcast(BaseComponent message);
|
||||
|
||||
/**
|
||||
* Gets a new instance of this proxies custom tab list.
|
||||
*
|
||||
* @param player the player to generate this list in the context of
|
||||
* @return a new {@link CustomTabList} instance
|
||||
*/
|
||||
public abstract CustomTabList customTabList(ProxiedPlayer player);
|
||||
|
||||
/**
|
||||
* Gets the commands which are disabled and will not be run on this proxy.
|
||||
*
|
||||
|
@ -3,7 +3,6 @@ package net.md_5.bungee.api.config;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
|
||||
/**
|
||||
* Class representing the configuration of a server listener. Used for allowing
|
||||
@ -49,12 +48,9 @@ public class ListenerInfo
|
||||
*/
|
||||
private final Map<String, String> forcedHosts;
|
||||
/**
|
||||
* Class used to build tab lists for this player.
|
||||
*
|
||||
* @deprecated Future Minecraft versions render this API useless
|
||||
* The type of tab list to use
|
||||
*/
|
||||
@Deprecated
|
||||
private final Class<? extends TabListHandler> tabList;
|
||||
private final String tabListType;
|
||||
/**
|
||||
* Whether to set the local address when connecting to servers.
|
||||
*/
|
||||
|
@ -4,7 +4,6 @@ import java.util.Locale;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -86,25 +85,6 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
||||
*/
|
||||
void chat(String message);
|
||||
|
||||
/**
|
||||
* Sets the new tab list for the user. At this stage it is not advisable to
|
||||
* change after the user has logged in!
|
||||
*
|
||||
* @param list the new list
|
||||
* @deprecated Future Minecraft versions render this API useless
|
||||
*/
|
||||
@Deprecated
|
||||
void setTabList(TabListHandler list);
|
||||
|
||||
/**
|
||||
* Get the current tab list.
|
||||
*
|
||||
* @return the tab list in use by this user
|
||||
* @deprecated Future Minecraft versions render this API useless
|
||||
*/
|
||||
@Deprecated
|
||||
TabListHandler getTabList();
|
||||
|
||||
/**
|
||||
* Get the server which this player will be sent to next time the log in.
|
||||
*
|
||||
|
@ -1,63 +0,0 @@
|
||||
package net.md_5.bungee.api.tab;
|
||||
|
||||
/**
|
||||
* Represents a custom tab list, which may have slots manipulated.
|
||||
*
|
||||
* @deprecated Future Minecraft versions render this API useless
|
||||
*/
|
||||
@Deprecated
|
||||
public interface CustomTabList extends TabListHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Blank out this tab list and update immediately.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Gets the columns in this list.
|
||||
*
|
||||
* @return the width of this list
|
||||
*/
|
||||
int getColumns();
|
||||
|
||||
/**
|
||||
* Gets the rows in this list.
|
||||
*
|
||||
* @return the height of this list
|
||||
*/
|
||||
int getRows();
|
||||
|
||||
/**
|
||||
* Get the total size of this list.
|
||||
*
|
||||
* @return {@link #getRows()} * {@link #getColumns()}
|
||||
*/
|
||||
int getSize();
|
||||
|
||||
/**
|
||||
* Set the text in the specified slot and update immediately.
|
||||
*
|
||||
* @param row the row to set
|
||||
* @param column the column to set
|
||||
* @param text the text to set
|
||||
* @return the padded text
|
||||
*/
|
||||
String setSlot(int row, int column, String text);
|
||||
|
||||
/**
|
||||
* Set the text in the specified slot.
|
||||
*
|
||||
* @param row the row to set
|
||||
* @param column the column to set
|
||||
* @param text the text to set
|
||||
* @param update whether or not to invoke {@link #update()} upon completion
|
||||
* @return the padded text
|
||||
*/
|
||||
String setSlot(int row, int column, String text, boolean update);
|
||||
|
||||
/**
|
||||
* Flush all queued changes to the user.
|
||||
*/
|
||||
void update();
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package net.md_5.bungee.api.tab;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
/**
|
||||
* @deprecated Future Minecraft versions render this API useless
|
||||
*/
|
||||
@Deprecated
|
||||
@NoArgsConstructor
|
||||
public abstract class TabListAdapter implements TabListHandler
|
||||
{
|
||||
|
||||
@Getter
|
||||
private ProxiedPlayer player;
|
||||
|
||||
@Override
|
||||
public void init(ProxiedPlayer player)
|
||||
{
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPingChange(int ping)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package net.md_5.bungee.api.tab;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
/**
|
||||
* @deprecated Future Minecraft versions render this API useless
|
||||
*/
|
||||
@Deprecated
|
||||
public interface TabListHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Called so that this class may set member fields to keep track of its
|
||||
* internal state. You should not do any packet sending or manipulation of
|
||||
* the passed player, other than storing it.
|
||||
*
|
||||
* @param player the player to be associated with this list
|
||||
*/
|
||||
void init(ProxiedPlayer player);
|
||||
|
||||
/**
|
||||
* Called when this player first connects to the proxy.
|
||||
*/
|
||||
void onConnect();
|
||||
|
||||
/**
|
||||
* Called when a player first connects to the proxy.
|
||||
*/
|
||||
void onServerChange();
|
||||
|
||||
/**
|
||||
* Called when a players ping changes. The new ping will have not updated in
|
||||
* the player instance until this method returns.
|
||||
*
|
||||
* @param ping the player's new ping.
|
||||
*/
|
||||
void onPingChange(int ping);
|
||||
|
||||
/**
|
||||
* Called when a player disconnects.
|
||||
*/
|
||||
void onDisconnect();
|
||||
|
||||
/**
|
||||
* Called when a list update packet is sent from server to client.
|
||||
*
|
||||
* @param name the player which this packet is relevant to
|
||||
* @param online whether the subject player is online
|
||||
* @param ping ping of the subject player
|
||||
* @return whether to send the packet to the client
|
||||
*/
|
||||
boolean onListUpdate(String name, boolean online, int ping);
|
||||
}
|
@ -7,6 +7,7 @@ import net.md_5.bungee.protocol.packet.Login;
|
||||
import net.md_5.bungee.protocol.packet.Chat;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
import net.md_5.bungee.protocol.packet.SetCompression;
|
||||
import net.md_5.bungee.protocol.packet.TabCompleteRequest;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardScore;
|
||||
@ -128,4 +129,8 @@ public abstract class AbstractPacketHandler
|
||||
public void handle(LegacyHandshake legacyHandshake) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(SetCompression setCompression) throws Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class DefinedPacket
|
||||
{
|
||||
@ -29,7 +31,7 @@ public abstract class DefinedPacket
|
||||
return new String( b, Charsets.UTF_8 );
|
||||
}
|
||||
|
||||
public static void writeArray(byte[] b, ByteBuf buf)
|
||||
public static void writeArrayLegacy(byte[] b, ByteBuf buf)
|
||||
{
|
||||
Preconditions.checkArgument( b.length <= Short.MAX_VALUE, "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length );
|
||||
|
||||
@ -37,7 +39,7 @@ public abstract class DefinedPacket
|
||||
buf.writeBytes( b );
|
||||
}
|
||||
|
||||
public static byte[] readArray(ByteBuf buf)
|
||||
public static byte[] readArrayLegacy(ByteBuf buf)
|
||||
{
|
||||
short len = buf.readShort();
|
||||
Preconditions.checkArgument( len <= Short.MAX_VALUE, "Cannot receive array longer than Short.MAX_VALUE (got %s bytes)", len );
|
||||
@ -47,6 +49,19 @@ public abstract class DefinedPacket
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void writeArray(byte[] b, ByteBuf buf)
|
||||
{
|
||||
writeVarInt( b.length, buf );
|
||||
buf.writeBytes( b );
|
||||
}
|
||||
|
||||
public static byte[] readArray(ByteBuf buf)
|
||||
{
|
||||
byte[] ret = new byte[ readVarInt( buf ) ];
|
||||
buf.readBytes( ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void writeStringArray(String[] s, ByteBuf buf)
|
||||
{
|
||||
writeVarInt( s.length, buf );
|
||||
@ -114,6 +129,17 @@ public abstract class DefinedPacket
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeUUID(UUID value, ByteBuf output)
|
||||
{
|
||||
output.writeLong( value.getMostSignificantBits() );
|
||||
output.writeLong( value.getLeastSignificantBits() );
|
||||
}
|
||||
|
||||
public static UUID readUUID(ByteBuf input)
|
||||
{
|
||||
return new UUID( input.readLong(), input.readLong() );
|
||||
}
|
||||
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
throw new UnsupportedOperationException( "Packet must implement read method" );
|
||||
|
@ -0,0 +1,43 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public class PacketCompressor extends MessageToByteEncoder<ByteBuf>
|
||||
{
|
||||
|
||||
private final byte[] buffer = new byte[ 8192 ];
|
||||
private final Deflater deflater = new Deflater();
|
||||
@Setter
|
||||
private int threshold = 256;
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception
|
||||
{
|
||||
int origSize = msg.readableBytes();
|
||||
if ( origSize < threshold )
|
||||
{
|
||||
DefinedPacket.writeVarInt( 0, out );
|
||||
out.writeBytes( msg );
|
||||
} else
|
||||
{
|
||||
byte[] data = new byte[ origSize ];
|
||||
msg.readBytes( data );
|
||||
|
||||
DefinedPacket.writeVarInt( data.length, out );
|
||||
|
||||
deflater.setInput( data );
|
||||
deflater.finish();
|
||||
while ( !deflater.finished() )
|
||||
{
|
||||
int count = deflater.deflate( buffer );
|
||||
out.writeBytes( buffer, 0, count );
|
||||
}
|
||||
deflater.reset();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class PacketDecompressor extends ByteToMessageDecoder
|
||||
{
|
||||
|
||||
private final Inflater inflater = new Inflater();
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception
|
||||
{
|
||||
if ( in.readableBytes() == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int size = DefinedPacket.readVarInt( in );
|
||||
if ( size == 0 )
|
||||
{
|
||||
out.add( in.readBytes( in.readableBytes() ) );
|
||||
} else
|
||||
{
|
||||
byte[] compressedData = new byte[ in.readableBytes() ];
|
||||
in.readBytes( compressedData );
|
||||
inflater.setInput( compressedData );
|
||||
|
||||
byte[] data = new byte[ size ];
|
||||
inflater.inflate( data );
|
||||
out.add( Unpooled.wrappedBuffer( data ) );
|
||||
inflater.reset();
|
||||
}
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardScore;
|
||||
import net.md_5.bungee.protocol.packet.SetCompression;
|
||||
import net.md_5.bungee.protocol.packet.StatusRequest;
|
||||
import net.md_5.bungee.protocol.packet.StatusResponse;
|
||||
import net.md_5.bungee.protocol.packet.TabCompleteRequest;
|
||||
@ -59,6 +60,7 @@ public enum Protocol
|
||||
TO_CLIENT.registerPacket( 0x3E, Team.class );
|
||||
TO_CLIENT.registerPacket( 0x3F, PluginMessage.class );
|
||||
TO_CLIENT.registerPacket( 0x40, Kick.class );
|
||||
TO_CLIENT.registerPacket( 0x46, SetCompression.class );
|
||||
|
||||
TO_SERVER.registerPacket( 0x00, KeepAlive.class );
|
||||
TO_SERVER.registerPacket( 0x01, Chat.class );
|
||||
@ -87,6 +89,7 @@ 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_SERVER.registerPacket( 0x00, LoginRequest.class );
|
||||
TO_SERVER.registerPacket( 0x01, EncryptionResponse.class );
|
||||
@ -94,7 +97,11 @@ public enum Protocol
|
||||
};
|
||||
/*========================================================================*/
|
||||
public static final int MAX_PACKET_ID = 0xFF;
|
||||
public static List<Integer> supportedVersions = Arrays.asList( ProtocolConstants.MINECRAFT_1_7_2, ProtocolConstants.MINECRAFT_1_7_6, ProtocolConstants.MINECRAFT_14_11_a );
|
||||
public static List<Integer> supportedVersions = Arrays.asList(
|
||||
ProtocolConstants.MINECRAFT_1_7_2,
|
||||
ProtocolConstants.MINECRAFT_1_7_6,
|
||||
ProtocolConstants.MINECRAFT_SNAPSHOT
|
||||
);
|
||||
/*========================================================================*/
|
||||
public final DirectionData TO_SERVER = new DirectionData( ProtocolConstants.Direction.TO_SERVER );
|
||||
public final DirectionData TO_CLIENT = new DirectionData( ProtocolConstants.Direction.TO_CLIENT );
|
||||
|
@ -5,7 +5,7 @@ public class ProtocolConstants
|
||||
|
||||
public static final int MINECRAFT_1_7_2 = 4;
|
||||
public static final int MINECRAFT_1_7_6 = 5;
|
||||
public static final int MINECRAFT_14_11_a = 14;
|
||||
public static final int MINECRAFT_SNAPSHOT = 46;
|
||||
|
||||
public enum Direction
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ public class Chat extends DefinedPacket
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
message = readString( buf );
|
||||
if ( direction == ProtocolConstants.Direction.TO_CLIENT && protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( direction == ProtocolConstants.Direction.TO_CLIENT && protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
position = buf.readByte();
|
||||
}
|
||||
@ -38,7 +38,7 @@ public class Chat extends DefinedPacket
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
writeString( message, buf );
|
||||
if ( direction == ProtocolConstants.Direction.TO_CLIENT && protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( direction == ProtocolConstants.Direction.TO_CLIENT && protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
buf.writeByte( position );
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -20,20 +21,34 @@ public class EncryptionRequest extends DefinedPacket
|
||||
private byte[] verifyToken;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
serverId = readString( buf );
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
publicKey = readArrayLegacy( buf );
|
||||
verifyToken = readArrayLegacy( buf );
|
||||
} else
|
||||
{
|
||||
publicKey = readArray( buf );
|
||||
verifyToken = readArray( buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
writeString( serverId, buf );
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeArrayLegacy( publicKey, buf );
|
||||
writeArrayLegacy( verifyToken, buf );
|
||||
} else
|
||||
{
|
||||
writeArray( publicKey, buf );
|
||||
writeArray( verifyToken, buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
|
@ -7,6 +7,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -19,18 +20,32 @@ public class EncryptionResponse extends DefinedPacket
|
||||
private byte[] verifyToken;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
sharedSecret = readArrayLegacy( buf );
|
||||
verifyToken = readArrayLegacy( buf );
|
||||
} else
|
||||
{
|
||||
sharedSecret = readArray( buf );
|
||||
verifyToken = readArray( buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeArrayLegacy( sharedSecret, buf );
|
||||
writeArrayLegacy( verifyToken, buf );
|
||||
} else
|
||||
{
|
||||
writeArray( sharedSecret, buf );
|
||||
writeArray( verifyToken, buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
|
@ -21,7 +21,7 @@ public class KeepAlive extends DefinedPacket
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
if ( direction == ProtocolConstants.Direction.TO_SERVER && protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
randomId = readVarInt( buf );
|
||||
} else
|
||||
@ -33,7 +33,7 @@ public class KeepAlive extends DefinedPacket
|
||||
@Override
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
if ( direction == ProtocolConstants.Direction.TO_SERVER && protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeVarInt( randomId, buf );
|
||||
} else
|
||||
|
@ -7,6 +7,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -21,9 +22,10 @@ public class Login extends DefinedPacket
|
||||
private short difficulty;
|
||||
private short maxPlayers;
|
||||
private String levelType;
|
||||
private boolean reducedDebugInfo;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
entityId = buf.readInt();
|
||||
gameMode = buf.readUnsignedByte();
|
||||
@ -31,10 +33,14 @@ public class Login extends DefinedPacket
|
||||
difficulty = buf.readUnsignedByte();
|
||||
maxPlayers = buf.readUnsignedByte();
|
||||
levelType = readString( buf );
|
||||
if ( protocolVersion >= 29 )
|
||||
{
|
||||
reducedDebugInfo = buf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
buf.writeInt( entityId );
|
||||
buf.writeByte( gameMode );
|
||||
@ -42,6 +48,10 @@ public class Login extends DefinedPacket
|
||||
buf.writeByte( difficulty );
|
||||
buf.writeByte( maxPlayers );
|
||||
writeString( levelType, buf );
|
||||
if ( protocolVersion >= 29 )
|
||||
{
|
||||
buf.writeBoolean( reducedDebugInfo );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,49 +2,144 @@ package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PlayerListItem extends DefinedPacket
|
||||
{
|
||||
|
||||
private String username;
|
||||
private boolean online;
|
||||
private int ping;
|
||||
private Action action;
|
||||
private Item[] items;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
username = readString( buf );
|
||||
online = buf.readBoolean();
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
ping = readVarInt( buf );
|
||||
items = new Item[ 1 ];
|
||||
Item item = items[ 0 ] = new Item();
|
||||
item.displayName = item.username = readString( buf );
|
||||
action = !buf.readBoolean() ? Action.REMOVE_PLAYER : Action.ADD_PLAYER;
|
||||
item.ping = buf.readShort();
|
||||
} else
|
||||
{
|
||||
ping = buf.readShort();
|
||||
action = Action.values()[ DefinedPacket.readVarInt( buf )];
|
||||
items = new Item[ DefinedPacket.readVarInt( buf ) ];
|
||||
for ( int i = 0; i < items.length; i++ )
|
||||
{
|
||||
Item item = items[ i ] = new Item();
|
||||
item.setUuid( DefinedPacket.readUUID( buf ) );
|
||||
switch ( action )
|
||||
{
|
||||
case ADD_PLAYER:
|
||||
item.username = DefinedPacket.readString( buf );
|
||||
item.properties = new String[ DefinedPacket.readVarInt( buf ) ][];
|
||||
for ( int j = 0; j < item.properties.length; j++ )
|
||||
{
|
||||
String name = DefinedPacket.readString( buf );
|
||||
String value = DefinedPacket.readString( buf );
|
||||
if ( buf.readBoolean() )
|
||||
{
|
||||
item.properties[ j] = new String[]
|
||||
{
|
||||
name, value, DefinedPacket.readString( buf )
|
||||
};
|
||||
} else
|
||||
{
|
||||
item.properties[ j ] = new String[]
|
||||
{
|
||||
name, value
|
||||
};
|
||||
}
|
||||
}
|
||||
item.gamemode = DefinedPacket.readVarInt( buf );
|
||||
item.ping = DefinedPacket.readVarInt( buf );
|
||||
if ( buf.readBoolean() )
|
||||
{
|
||||
item.displayName = DefinedPacket.readString( buf );
|
||||
}
|
||||
break;
|
||||
case UPDATE_GAMEMODE:
|
||||
item.gamemode = DefinedPacket.readVarInt( buf );
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
item.ping = DefinedPacket.readVarInt( buf );
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
if ( buf.readBoolean() )
|
||||
{
|
||||
item.displayName = DefinedPacket.readString( buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
writeString( username, buf );
|
||||
buf.writeBoolean( online );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeVarInt( ping, buf );
|
||||
Item item = items[0]; // Only one at a time
|
||||
writeString( item.displayName, buf );
|
||||
buf.writeBoolean( action != Action.REMOVE_PLAYER );
|
||||
buf.writeShort( item.ping );
|
||||
} else
|
||||
{
|
||||
buf.writeShort( ping );
|
||||
DefinedPacket.writeVarInt( action.ordinal(), buf );
|
||||
DefinedPacket.writeVarInt( items.length, buf );
|
||||
for ( Item item : items )
|
||||
{
|
||||
DefinedPacket.writeUUID( item.uuid, buf );
|
||||
switch ( action )
|
||||
{
|
||||
case ADD_PLAYER:
|
||||
DefinedPacket.writeString( item.username, buf );
|
||||
DefinedPacket.writeVarInt( item.properties.length, buf );
|
||||
for ( String[] prop : item.properties )
|
||||
{
|
||||
DefinedPacket.writeString( prop[ 0], buf );
|
||||
DefinedPacket.writeString( prop[ 1], buf );
|
||||
if ( prop.length >= 3 )
|
||||
{
|
||||
buf.writeBoolean( true );
|
||||
DefinedPacket.writeString( prop[ 2], buf );
|
||||
} else
|
||||
{
|
||||
buf.writeBoolean( false );
|
||||
}
|
||||
}
|
||||
DefinedPacket.writeVarInt( item.gamemode, buf );
|
||||
DefinedPacket.writeVarInt( item.ping, buf );
|
||||
buf.writeBoolean( item.displayName != null );
|
||||
if ( item.displayName != null )
|
||||
{
|
||||
DefinedPacket.writeString( item.displayName, buf );
|
||||
}
|
||||
break;
|
||||
case UPDATE_GAMEMODE:
|
||||
DefinedPacket.writeVarInt( item.gamemode, buf );
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
DefinedPacket.writeVarInt( item.ping, buf );
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
buf.writeBoolean( item.displayName != null );
|
||||
if ( item.displayName != null )
|
||||
{
|
||||
DefinedPacket.writeString( item.displayName, buf );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,4 +148,36 @@ public class PlayerListItem extends DefinedPacket
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
|
||||
public static enum Action
|
||||
{
|
||||
|
||||
ADD_PLAYER,
|
||||
UPDATE_GAMEMODE,
|
||||
UPDATE_LATENCY,
|
||||
UPDATE_DISPLAY_NAME,
|
||||
REMOVE_PLAYER;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Item
|
||||
{
|
||||
|
||||
// ALL
|
||||
private UUID uuid;
|
||||
|
||||
// ADD_PLAYER
|
||||
private String username;
|
||||
private String[][] properties;
|
||||
|
||||
// ADD_PLAYER & UPDATE_GAMEMODE
|
||||
private int gamemode;
|
||||
|
||||
// ADD_PLAYER & UPDATE_LATENCY
|
||||
private int ping;
|
||||
|
||||
// ADD_PLAYER & UPDATE_DISPLAY_NAME
|
||||
private String displayName;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.MinecraftInput;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -24,17 +25,30 @@ public class PluginMessage extends DefinedPacket
|
||||
private byte[] data;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
tag = readString( buf );
|
||||
data = readArray( buf );
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
data = readArrayLegacy( buf );
|
||||
} else
|
||||
{
|
||||
data = new byte[ buf.readableBytes() ];
|
||||
buf.readBytes( data );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
writeString( tag, buf );
|
||||
writeArray( data, buf );
|
||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeArrayLegacy( data, buf );
|
||||
} else
|
||||
{
|
||||
buf.writeBytes( data );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,7 +33,7 @@ public class ScoreboardObjective extends DefinedPacket
|
||||
value = readString( buf );
|
||||
}
|
||||
action = buf.readByte();
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a && ( action == 0 || action == 2 ) )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT && ( action == 0 || action == 2 ) )
|
||||
{
|
||||
value = readString( buf );
|
||||
type = readString( buf );
|
||||
@ -49,7 +49,7 @@ public class ScoreboardObjective extends DefinedPacket
|
||||
writeString( value, buf );
|
||||
}
|
||||
buf.writeByte( action );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a && ( action == 0 || action == 2 ) )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT && ( action == 0 || action == 2 ) )
|
||||
{
|
||||
writeString( value, buf );
|
||||
writeString( type, buf );
|
||||
|
@ -29,14 +29,18 @@ public class ScoreboardScore extends DefinedPacket
|
||||
{
|
||||
itemName = readString( buf );
|
||||
action = buf.readByte();
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
scoreName = readString( buf );
|
||||
if ( action != 1 )
|
||||
{
|
||||
value = readVarInt( buf );
|
||||
}
|
||||
} else
|
||||
{
|
||||
if ( action != 1 )
|
||||
{
|
||||
scoreName = readString( buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
{
|
||||
value = readVarInt( buf );
|
||||
} else
|
||||
{
|
||||
value = buf.readInt();
|
||||
}
|
||||
}
|
||||
@ -47,14 +51,18 @@ public class ScoreboardScore extends DefinedPacket
|
||||
{
|
||||
writeString( itemName, buf );
|
||||
buf.writeByte( action );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeString( scoreName, buf );
|
||||
if ( action != 1 )
|
||||
{
|
||||
writeVarInt( value, buf );
|
||||
}
|
||||
} else
|
||||
{
|
||||
if ( action != 1 )
|
||||
{
|
||||
writeString( scoreName, buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
{
|
||||
writeVarInt( value, buf );
|
||||
} else
|
||||
{
|
||||
buf.writeInt( value );
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class SetCompression extends DefinedPacket
|
||||
{
|
||||
|
||||
private int threshold;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
threshold = DefinedPacket.readVarInt( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
DefinedPacket.writeVarInt( threshold, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -16,17 +17,34 @@ public class TabCompleteRequest extends DefinedPacket
|
||||
{
|
||||
|
||||
private String cursor;
|
||||
private boolean hasPositon;
|
||||
private long position;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
cursor = readString( buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
if ( hasPositon = buf.readBoolean() )
|
||||
{
|
||||
position = buf.readLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
writeString( cursor, buf );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
buf.writeBoolean( hasPositon );
|
||||
if ( hasPositon )
|
||||
{
|
||||
buf.writeLong( position );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,7 +50,7 @@ public class Team extends DefinedPacket
|
||||
prefix = readString( buf );
|
||||
suffix = readString( buf );
|
||||
friendlyFire = buf.readByte();
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
nameTagVisibility = readString( buf );
|
||||
color = buf.readByte();
|
||||
@ -58,7 +58,7 @@ public class Team extends DefinedPacket
|
||||
}
|
||||
if ( mode == 0 || mode == 3 || mode == 4 )
|
||||
{
|
||||
int len = ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a ) ? readVarInt( buf ) : buf.readShort();
|
||||
int len = ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT ) ? readVarInt( buf ) : buf.readShort();
|
||||
players = new String[ len ];
|
||||
for ( int i = 0; i < len; i++ )
|
||||
{
|
||||
@ -78,7 +78,7 @@ public class Team extends DefinedPacket
|
||||
writeString( prefix, buf );
|
||||
writeString( suffix, buf );
|
||||
buf.writeByte( friendlyFire );
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeString( nameTagVisibility, buf );
|
||||
buf.writeByte( color );
|
||||
@ -86,7 +86,7 @@ public class Team extends DefinedPacket
|
||||
}
|
||||
if ( mode == 0 || mode == 3 || mode == 4 )
|
||||
{
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_14_11_a )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
writeVarInt( players.length, buf );
|
||||
} else
|
||||
|
@ -36,6 +36,7 @@ import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -65,7 +66,6 @@ import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.plugin.PluginManager;
|
||||
import net.md_5.bungee.api.tab.CustomTabList;
|
||||
import net.md_5.bungee.command.*;
|
||||
import net.md_5.bungee.conf.YamlConfig;
|
||||
import net.md_5.bungee.log.LoggingOutputStream;
|
||||
@ -76,7 +76,6 @@ import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import net.md_5.bungee.protocol.packet.Chat;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
import net.md_5.bungee.query.RemoteQuery;
|
||||
import net.md_5.bungee.tab.Custom;
|
||||
import net.md_5.bungee.util.CaseInsensitiveMap;
|
||||
import org.fusesource.jansi.AnsiConsole;
|
||||
|
||||
@ -113,6 +112,8 @@ public class BungeeCord extends ProxyServer
|
||||
* Fully qualified connections.
|
||||
*/
|
||||
private final Map<String, UserConnection> connections = new CaseInsensitiveMap<>();
|
||||
// Used to help with packet rewriting
|
||||
private final Map<UUID, UserConnection> connectionsByOfflineUUID = new HashMap<>();
|
||||
private final ReadWriteLock connectionLock = new ReentrantReadWriteLock();
|
||||
/**
|
||||
* Plugin manager.
|
||||
@ -468,6 +469,18 @@ public class BungeeCord extends ProxyServer
|
||||
}
|
||||
}
|
||||
|
||||
public UserConnection getPlayerByOfflineUUID(UUID name)
|
||||
{
|
||||
connectionLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
return connectionsByOfflineUUID.get( name );
|
||||
} finally
|
||||
{
|
||||
connectionLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxiedPlayer getPlayer(UUID uuid)
|
||||
{
|
||||
@ -577,6 +590,7 @@ public class BungeeCord extends ProxyServer
|
||||
try
|
||||
{
|
||||
connections.put( con.getName(), con );
|
||||
connectionsByOfflineUUID.put( con.getPendingConnection().getOfflineId(), con );
|
||||
} finally
|
||||
{
|
||||
connectionLock.writeLock().unlock();
|
||||
@ -589,19 +603,13 @@ public class BungeeCord extends ProxyServer
|
||||
try
|
||||
{
|
||||
connections.remove( con.getName() );
|
||||
connectionsByOfflineUUID.remove( con.getPendingConnection().getOfflineId() );
|
||||
} finally
|
||||
{
|
||||
connectionLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomTabList customTabList(ProxiedPlayer player)
|
||||
{
|
||||
return new Custom( player );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getDisabledCommands()
|
||||
{
|
||||
return config.getDisabledCommands();
|
||||
|
@ -31,6 +31,7 @@ import net.md_5.bungee.protocol.packet.ScoreboardObjective;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
import net.md_5.bungee.protocol.packet.LoginSuccess;
|
||||
import net.md_5.bungee.protocol.packet.SetCompression;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ServerConnector extends PacketHandler
|
||||
@ -102,6 +103,13 @@ public class ServerConnector extends PacketHandler
|
||||
throw CancelSendSignal.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(SetCompression setCompression) throws Exception
|
||||
{
|
||||
user.setCompressionThreshold( setCompression.getThreshold() );
|
||||
ch.setCompressionThreshold( setCompression.getThreshold() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Login login) throws Exception
|
||||
{
|
||||
@ -139,7 +147,7 @@ public class ServerConnector extends PacketHandler
|
||||
|
||||
// Set tab list size, this sucks balls, TODO: what shall we do about packet mutability
|
||||
Login modLogin = new Login( login.getEntityId(), login.getGameMode(), (byte) login.getDimension(), login.getDifficulty(),
|
||||
(byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType() );
|
||||
(byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.isReducedDebugInfo() );
|
||||
|
||||
user.unsafe().sendPacket( modLogin );
|
||||
|
||||
@ -148,7 +156,7 @@ public class ServerConnector extends PacketHandler
|
||||
user.unsafe().sendPacket( new PluginMessage( "MC|Brand", out.toArray() ) );
|
||||
} else
|
||||
{
|
||||
user.getTabList().onServerChange();
|
||||
user.getTabListHandler().onServerChange();
|
||||
|
||||
Scoreboard serverScoreboard = user.getServerSentScoreboard();
|
||||
for ( Objective objective : serverScoreboard.getObjectives() )
|
||||
|
@ -30,7 +30,6 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PermissionCheckEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
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;
|
||||
@ -46,6 +45,11 @@ import net.md_5.bungee.protocol.packet.Chat;
|
||||
import net.md_5.bungee.protocol.packet.ClientSettings;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
import net.md_5.bungee.protocol.packet.SetCompression;
|
||||
import net.md_5.bungee.tab.Global;
|
||||
import net.md_5.bungee.tab.GlobalPing;
|
||||
import net.md_5.bungee.tab.ServerUnique;
|
||||
import net.md_5.bungee.tab.TabList;
|
||||
import net.md_5.bungee.util.CaseInsensitiveSet;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@ -73,8 +77,6 @@ public final class UserConnection implements ProxiedPlayer
|
||||
private final Collection<ServerInfo> pendingConnects = new HashSet<>();
|
||||
/*========================================================================*/
|
||||
@Getter
|
||||
private TabListHandler tabList;
|
||||
@Getter
|
||||
@Setter
|
||||
private int sentPingId;
|
||||
@Getter
|
||||
@ -86,6 +88,13 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@Getter
|
||||
@Setter
|
||||
private ServerInfo reconnectServer;
|
||||
@Getter
|
||||
private TabList tabListHandler;
|
||||
@Getter
|
||||
@Setter
|
||||
private int gamemode;
|
||||
@Getter
|
||||
private int compressionThreshold = -1;
|
||||
/*========================================================================*/
|
||||
private final Collection<String> groups = new CaseInsensitiveSet();
|
||||
private final Collection<String> permissions = new CaseInsensitiveSet();
|
||||
@ -121,14 +130,19 @@ public final class UserConnection implements ProxiedPlayer
|
||||
this.entityRewrite = EntityMap.getEntityMap( getPendingConnection().getVersion() );
|
||||
|
||||
this.displayName = name;
|
||||
try
|
||||
|
||||
switch ( getPendingConnection().getListener().getTabListType() )
|
||||
{
|
||||
this.tabList = getPendingConnection().getListener().getTabList().getDeclaredConstructor().newInstance();
|
||||
} catch ( ReflectiveOperationException ex )
|
||||
{
|
||||
throw new RuntimeException( ex );
|
||||
case "GLOBAL":
|
||||
tabListHandler = new Global( this );
|
||||
break;
|
||||
case "SERVER":
|
||||
tabListHandler = new ServerUnique( this );
|
||||
break;
|
||||
default:
|
||||
tabListHandler = new GlobalPing( this );
|
||||
break;
|
||||
}
|
||||
this.tabList.init( this );
|
||||
|
||||
Collection<String> g = bungee.getConfigurationAdapter().getGroups( name );
|
||||
for ( String s : g )
|
||||
@ -137,13 +151,6 @@ public final class UserConnection implements ProxiedPlayer
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTabList(TabListHandler tabList)
|
||||
{
|
||||
tabList.init( this );
|
||||
this.tabList = tabList;
|
||||
}
|
||||
|
||||
public void sendPacket(PacketWrapper packet)
|
||||
{
|
||||
ch.write( packet );
|
||||
@ -160,9 +167,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
{
|
||||
Preconditions.checkNotNull( name, "displayName" );
|
||||
Preconditions.checkArgument( name.length() <= 16, "Display name cannot be longer than 16 characters" );
|
||||
getTabList().onDisconnect();
|
||||
displayName = name;
|
||||
getTabList().onConnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -461,4 +466,14 @@ public final class UserConnection implements ProxiedPlayer
|
||||
{
|
||||
return ( locale == null && settings != null ) ? locale = Locale.forLanguageTag( settings.getLocale().replaceAll( "_", "-" ) ) : locale;
|
||||
}
|
||||
|
||||
public void setCompressionThreshold(int compressionThreshold)
|
||||
{
|
||||
if ( this.compressionThreshold == -1 )
|
||||
{
|
||||
this.compressionThreshold = compressionThreshold;
|
||||
unsafe.sendPacket( new SetCompression( compressionThreshold ) );
|
||||
ch.setCompressionThreshold( compressionThreshold );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,6 @@ import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
import net.md_5.bungee.tab.Global;
|
||||
import net.md_5.bungee.tab.GlobalPing;
|
||||
import net.md_5.bungee.tab.ServerUnique;
|
||||
import net.md_5.bungee.util.CaseInsensitiveMap;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
@ -40,8 +36,7 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
private enum DefaultTabList
|
||||
{
|
||||
|
||||
GLOBAL( Global.class ), GLOBAL_PING( GlobalPing.class ), SERVER( ServerUnique.class );
|
||||
private final Class<? extends TabListHandler> clazz;
|
||||
GLOBAL(), GLOBAL_PING(), SERVER();
|
||||
}
|
||||
private final Yaml yaml;
|
||||
private Map config;
|
||||
@ -224,7 +219,7 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
boolean query = get( "query_enabled", false, val );
|
||||
int queryPort = get( "query_port", 25577, val );
|
||||
|
||||
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, forced, value.clazz, setLocalAddress, pingPassthrough, queryPort, query );
|
||||
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, forced, value.toString(), setLocalAddress, pingPassthrough, queryPort, query );
|
||||
ret.add( info );
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,8 @@ import net.md_5.bungee.protocol.packet.ScoreboardScore;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
import net.md_5.bungee.protocol.packet.SetCompression;
|
||||
import net.md_5.bungee.tab.TabList;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class DownstreamBridge extends PacketHandler
|
||||
@ -100,11 +102,8 @@ public class DownstreamBridge extends PacketHandler
|
||||
@Override
|
||||
public void handle(PlayerListItem playerList) throws Exception
|
||||
{
|
||||
|
||||
if ( !con.getTabList().onListUpdate( playerList.getUsername(), playerList.isOnline(), playerList.getPing() ) )
|
||||
{
|
||||
throw CancelSendSignal.INSTANCE;
|
||||
}
|
||||
con.getTabListHandler().onUpdate( TabList.rewrite( playerList ) );
|
||||
throw CancelSendSignal.INSTANCE; // Always throw because of profile rewriting
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -448,6 +447,13 @@ public class DownstreamBridge extends PacketHandler
|
||||
throw CancelSendSignal.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(SetCompression setCompression) throws Exception
|
||||
{
|
||||
con.setCompressionThreshold( setCompression.getThreshold() );
|
||||
server.getCh().setCompressionThreshold( setCompression.getThreshold() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ public class UpstreamBridge extends PacketHandler
|
||||
this.con = con;
|
||||
|
||||
BungeeCord.getInstance().addConnection( con );
|
||||
con.getTabList().onConnect();
|
||||
con.getTabListHandler().onConnect();
|
||||
con.unsafe().sendPacket( BungeeCord.getInstance().registerChannels() );
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ public class UpstreamBridge extends PacketHandler
|
||||
// We lost connection to the client
|
||||
PlayerDisconnectEvent event = new PlayerDisconnectEvent( con );
|
||||
bungee.getPluginManager().callEvent( event );
|
||||
con.getTabList().onDisconnect();
|
||||
con.getTabListHandler().onDisconnect();
|
||||
BungeeCord.getInstance().removeConnection( con );
|
||||
|
||||
if ( con.getServer() != null )
|
||||
@ -61,11 +61,8 @@ public class UpstreamBridge extends PacketHandler
|
||||
|
||||
@Override
|
||||
public void handle(PacketWrapper packet) throws Exception
|
||||
{
|
||||
if ( con.getPendingConnection().getVersion() <= ProtocolConstants.MINECRAFT_1_7_6 )
|
||||
{
|
||||
con.getEntityRewrite().rewriteServerbound( packet.buf, con.getClientEntityId(), con.getServerEntityId() );
|
||||
}
|
||||
if ( con.getServer() != null )
|
||||
{
|
||||
con.getServer().getCh().write( packet );
|
||||
@ -78,7 +75,7 @@ public class UpstreamBridge extends PacketHandler
|
||||
if ( alive.getRandomId() == con.getSentPingId() )
|
||||
{
|
||||
int newPing = (int) ( System.currentTimeMillis() - con.getSentPingTime() );
|
||||
con.getTabList().onPingChange( newPing );
|
||||
con.getTabListHandler().onPingChange( newPing );
|
||||
con.setPing( newPing );
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ public abstract class EntityMap
|
||||
return new EntityMap_1_7_2();
|
||||
case ProtocolConstants.MINECRAFT_1_7_6:
|
||||
return new EntityMap_1_7_6();
|
||||
case ProtocolConstants.MINECRAFT_14_11_a:
|
||||
return new EntityMap_14_11_a();
|
||||
case ProtocolConstants.MINECRAFT_SNAPSHOT:
|
||||
return new EntityMap_14_21_b();
|
||||
}
|
||||
throw new RuntimeException( "Version " + version + " has no entity map" );
|
||||
}
|
||||
|
@ -4,14 +4,15 @@ 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.connection.LoginResult;
|
||||
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_14_11_a extends EntityMap
|
||||
class EntityMap_14_21_b extends EntityMap
|
||||
{
|
||||
|
||||
EntityMap_14_11_a()
|
||||
EntityMap_14_21_b()
|
||||
{
|
||||
addRewrite( 0x04, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Equipment
|
||||
addRewrite( 0x0A, ProtocolConstants.Direction.TO_CLIENT, true ); // Use bed
|
||||
@ -38,6 +39,7 @@ class EntityMap_14_11_a extends EntityMap
|
||||
addRewrite( 0x25, ProtocolConstants.Direction.TO_CLIENT, true ); // Block Break Animation
|
||||
addRewrite( 0x2C, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Global Entity
|
||||
addRewrite( 0x43, ProtocolConstants.Direction.TO_CLIENT, true ); // Camera
|
||||
addRewrite( 0x49, ProtocolConstants.Direction.TO_CLIENT, true ); // Update Entity NBT
|
||||
|
||||
addRewrite( 0x02, ProtocolConstants.Direction.TO_SERVER, true ); // Use Entity
|
||||
addRewrite( 0x0B, ProtocolConstants.Direction.TO_SERVER, true ); // Entity Action
|
||||
@ -84,23 +86,24 @@ class EntityMap_14_11_a extends EntityMap
|
||||
}
|
||||
} else if ( packetId == 0x0E /* Spawn Object */ )
|
||||
{
|
||||
DefinedPacket.readVarInt( packet );
|
||||
int idLength = packet.readerIndex() - readerIndex - packetIdLength;
|
||||
|
||||
int type = packet.getByte( readerIndex + packetIdLength + idLength );
|
||||
DefinedPacket.readVarInt( packet );
|
||||
int type = packet.readUnsignedByte();
|
||||
|
||||
if ( type == 60 || type == 90 )
|
||||
{
|
||||
int readId = packet.getInt( packetIdLength + idLength + 15 );
|
||||
packet.skipBytes( 14 );
|
||||
int position = packet.readerIndex();
|
||||
int readId = packet.readInt();
|
||||
int changedId = -1;
|
||||
if ( readId == oldId )
|
||||
{
|
||||
packet.setInt( packetIdLength + idLength + 15, newId );
|
||||
packet.setInt( position, newId );
|
||||
changedId = newId;
|
||||
} else if ( readId == newId )
|
||||
{
|
||||
packet.setInt( packetIdLength + idLength + 15, oldId );
|
||||
changedId = newId;
|
||||
packet.setInt( position, oldId );
|
||||
changedId = oldId;
|
||||
}
|
||||
if ( changedId != -1 )
|
||||
{
|
||||
@ -118,36 +121,17 @@ class EntityMap_14_11_a extends EntityMap
|
||||
}
|
||||
} else if ( packetId == 0x0C /* Spawn Player */ )
|
||||
{
|
||||
DefinedPacket.readVarInt( packet );
|
||||
DefinedPacket.readVarInt( packet ); // Entity ID
|
||||
int idLength = packet.readerIndex() - readerIndex - packetIdLength;
|
||||
String uuid = DefinedPacket.readString( packet );
|
||||
String username = DefinedPacket.readString( packet );
|
||||
int props = DefinedPacket.readVarInt( packet );
|
||||
if ( props == 0 )
|
||||
UUID uuid = DefinedPacket.readUUID( packet );
|
||||
ProxiedPlayer player;
|
||||
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
|
||||
{
|
||||
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();
|
||||
int previous = packet.writerIndex();
|
||||
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();
|
||||
}
|
||||
}
|
||||
DefinedPacket.writeUUID( player.getUniqueId(), packet );
|
||||
packet.writerIndex( previous );
|
||||
}
|
||||
} else if ( packetId == 0x42 /* Combat Event */ )
|
||||
{
|
||||
@ -167,4 +151,29 @@ class EntityMap_14_11_a extends EntityMap
|
||||
}
|
||||
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 == 0x18 /* Spectate */ )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package net.md_5.bungee.netty;
|
||||
|
||||
import net.md_5.bungee.protocol.PacketCompressor;
|
||||
import net.md_5.bungee.protocol.PacketDecompressor;
|
||||
import net.md_5.bungee.protocol.PacketWrapper;
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.channel.Channel;
|
||||
@ -71,4 +73,28 @@ public class ChannelWrapper
|
||||
{
|
||||
return ch;
|
||||
}
|
||||
|
||||
public void setCompressionThreshold(int compressionThreshold)
|
||||
{
|
||||
if ( ch.pipeline().get( PacketCompressor.class ) == null && compressionThreshold != -1 )
|
||||
{
|
||||
addBefore( PipelineUtils.PACKET_ENCODER, "compress", new PacketCompressor() );
|
||||
}
|
||||
if ( compressionThreshold != -1 )
|
||||
{
|
||||
ch.pipeline().get( PacketCompressor.class ).setThreshold( compressionThreshold );
|
||||
} else
|
||||
{
|
||||
ch.pipeline().remove( "compress" );
|
||||
}
|
||||
|
||||
if ( ch.pipeline().get( PacketDecompressor.class ) == null && compressionThreshold != -1 )
|
||||
{
|
||||
addBefore( PipelineUtils.PACKET_DECODER, "decompress", new PacketDecompressor() );
|
||||
}
|
||||
if ( compressionThreshold == -1 )
|
||||
{
|
||||
ch.pipeline().remove( "decompress" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,158 +0,0 @@
|
||||
package net.md_5.bungee.tab;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.tab.CustomTabList;
|
||||
import net.md_5.bungee.api.tab.TabListAdapter;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
|
||||
public class Custom extends TabListAdapter implements CustomTabList
|
||||
{
|
||||
|
||||
private static final int ROWS = 20;
|
||||
private static final int COLUMNS = 3;
|
||||
private static final char[] FILLER = new char[]
|
||||
{
|
||||
'0', '1', '2', '2', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
private static final int MAX_LEN = 16;
|
||||
/*========================================================================*/
|
||||
private final Collection<String> sentStuff = new HashSet<>();
|
||||
/*========================================================================*/
|
||||
private final String[][] sent = new String[ ROWS ][ COLUMNS ];
|
||||
private final String[][] slots = new String[ ROWS ][ COLUMNS ];
|
||||
private int rowLim;
|
||||
private int colLim;
|
||||
|
||||
public Custom(ProxiedPlayer player)
|
||||
{
|
||||
this.init( player );
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String setSlot(int row, int column, String text)
|
||||
{
|
||||
return setSlot( row, column, text, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String setSlot(int row, int column, String text, boolean update)
|
||||
{
|
||||
Preconditions.checkArgument( row > 0 && row <= ROWS, "row out of range" );
|
||||
Preconditions.checkArgument( column > 0 && column <= COLUMNS, "column out of range" );
|
||||
|
||||
if ( text != null )
|
||||
{
|
||||
Preconditions.checkArgument( text.length() <= MAX_LEN - 2, "text must be <= %s chars", MAX_LEN - 2 );
|
||||
Preconditions.checkArgument( !ChatColor.stripColor( text ).isEmpty(), "Text cannot consist entirely of colour codes" );
|
||||
text = attempt( text );
|
||||
sentStuff.add( text );
|
||||
|
||||
if ( rowLim < row || colLim < column )
|
||||
{
|
||||
rowLim = row;
|
||||
colLim = column;
|
||||
}
|
||||
}
|
||||
|
||||
slots[--row][--column] = text;
|
||||
if ( update )
|
||||
{
|
||||
update();
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private String attempt(String s)
|
||||
{
|
||||
for ( char c : FILLER )
|
||||
{
|
||||
String attempt = s + Character.toString( ChatColor.COLOR_CHAR ) + c;
|
||||
if ( !sentStuff.contains( attempt ) )
|
||||
{
|
||||
return attempt;
|
||||
}
|
||||
}
|
||||
if ( s.length() <= MAX_LEN - 4 )
|
||||
{
|
||||
return attempt( s + Character.toString( ChatColor.COLOR_CHAR ) + FILLER[0] );
|
||||
}
|
||||
throw new IllegalArgumentException( "List already contains all variants of string" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void update()
|
||||
{
|
||||
clear();
|
||||
for ( int i = 0; i < rowLim; i++ )
|
||||
{
|
||||
for ( int j = 0; j < colLim; j++ )
|
||||
{
|
||||
String text = ( slots[i][j] != null ) ? slots[i][j] : new StringBuilder().append( base( i ) ).append( base( j ) ).toString();
|
||||
sent[i][j] = text;
|
||||
getPlayer().unsafe().sendPacket( new PlayerListItem( text, true, (short) 0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clear()
|
||||
{
|
||||
for ( int i = 0; i < rowLim; i++ )
|
||||
{
|
||||
for ( int j = 0; j < colLim; j++ )
|
||||
{
|
||||
if ( sent[i][j] != null )
|
||||
{
|
||||
String text = sent[i][j];
|
||||
sent[i][j] = null;
|
||||
getPlayer().unsafe().sendPacket( new PlayerListItem( text, false, (short) 9999 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getRows()
|
||||
{
|
||||
return ROWS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getColumns()
|
||||
{
|
||||
return COLUMNS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getSize()
|
||||
{
|
||||
return ROWS * COLUMNS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onListUpdate(String name, boolean online, int ping)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private static char[] base(int n)
|
||||
{
|
||||
String hex = Integer.toHexString( n + 1 );
|
||||
char[] alloc = new char[ hex.length() * 2 ];
|
||||
for ( int i = 0; i < alloc.length; i++ )
|
||||
{
|
||||
if ( i % 2 == 0 )
|
||||
{
|
||||
alloc[i] = ChatColor.COLOR_CHAR;
|
||||
} else
|
||||
{
|
||||
alloc[i] = hex.charAt( i / 2 );
|
||||
}
|
||||
}
|
||||
return alloc;
|
||||
}
|
||||
}
|
@ -1,24 +1,30 @@
|
||||
package net.md_5.bungee.tab;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.tab.TabListAdapter;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import net.md_5.bungee.connection.LoginResult;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
|
||||
public class Global extends TabListAdapter
|
||||
import java.util.Collection;
|
||||
|
||||
public class Global extends TabList
|
||||
{
|
||||
|
||||
private boolean sentPing;
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
public Global(ProxiedPlayer player)
|
||||
{
|
||||
for ( ProxiedPlayer p : ProxyServer.getInstance().getPlayers() )
|
||||
{
|
||||
getPlayer().unsafe().sendPacket( new PlayerListItem( p.getDisplayName(), true, (short) p.getPing() ) );
|
||||
super( player );
|
||||
}
|
||||
BungeeCord.getInstance().broadcast( new PlayerListItem( getPlayer().getDisplayName(), true, (short) getPlayer().getPing() ) );
|
||||
|
||||
@Override
|
||||
public void onUpdate(PlayerListItem playerListItem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -27,19 +33,112 @@ public class Global extends TabListAdapter
|
||||
if ( !sentPing )
|
||||
{
|
||||
sentPing = true;
|
||||
BungeeCord.getInstance().broadcast( new PlayerListItem( getPlayer().getDisplayName(), true, (short) getPlayer().getPing() ) );
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction( PlayerListItem.Action.UPDATE_LATENCY );
|
||||
PlayerListItem.Item item = new PlayerListItem.Item();
|
||||
item.setUuid( player.getUniqueId() );
|
||||
item.setUsername( player.getName() );
|
||||
item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) );
|
||||
item.setPing( player.getPing() );
|
||||
packet.setItems( new PlayerListItem.Item[]
|
||||
{
|
||||
item
|
||||
} );
|
||||
BungeeCord.getInstance().broadcast( packet );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
PlayerListItem playerListItem = new PlayerListItem();
|
||||
playerListItem.setAction( PlayerListItem.Action.ADD_PLAYER );
|
||||
Collection<ProxiedPlayer> players = BungeeCord.getInstance().getPlayers();
|
||||
PlayerListItem.Item[] items = new PlayerListItem.Item[ players.size() ];
|
||||
playerListItem.setItems( items );
|
||||
int i = 0;
|
||||
for ( ProxiedPlayer p : players )
|
||||
{
|
||||
PlayerListItem.Item item = items[i++] = new PlayerListItem.Item();
|
||||
item.setUuid( p.getUniqueId() );
|
||||
item.setUsername( p.getName() );
|
||||
item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( p.getDisplayName() ) ) );
|
||||
LoginResult loginResult = ( (UserConnection) p ).getPendingConnection().getLoginProfile();
|
||||
String[][] props = new String[ loginResult.getProperties().length ][];
|
||||
for ( int j = 0; j < props.length; j++ )
|
||||
{
|
||||
props[ j] = new String[]
|
||||
{
|
||||
loginResult.getProperties()[j].getName(),
|
||||
loginResult.getProperties()[j].getValue(),
|
||||
loginResult.getProperties()[j].getSignature()
|
||||
};
|
||||
}
|
||||
item.setProperties( props );
|
||||
item.setGamemode( ( (UserConnection) p ).getGamemode() );
|
||||
item.setPing( p.getPing() );
|
||||
}
|
||||
if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
player.unsafe().sendPacket( playerListItem );
|
||||
} else
|
||||
{
|
||||
// Split up the packet
|
||||
for ( PlayerListItem.Item item : playerListItem.getItems() )
|
||||
{
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction( playerListItem.getAction() );
|
||||
PlayerListItem.Item[] it = new PlayerListItem.Item[ 1 ];
|
||||
it[0] = item;
|
||||
packet.setItems( it );
|
||||
player.unsafe().sendPacket( packet );
|
||||
}
|
||||
}
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction( PlayerListItem.Action.ADD_PLAYER );
|
||||
PlayerListItem.Item item = new PlayerListItem.Item();
|
||||
item.setUuid( player.getUniqueId() );
|
||||
item.setUsername( player.getName() );
|
||||
item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) );
|
||||
LoginResult loginResult = ( (UserConnection) player ).getPendingConnection().getLoginProfile();
|
||||
String[][] props = new String[ loginResult.getProperties().length ][];
|
||||
for ( int j = 0; j < props.length; j++ )
|
||||
{
|
||||
props[ j] = new String[]
|
||||
{
|
||||
loginResult.getProperties()[j].getName(),
|
||||
loginResult.getProperties()[j].getValue(),
|
||||
loginResult.getProperties()[j].getSignature()
|
||||
};
|
||||
}
|
||||
item.setProperties( props );
|
||||
item.setGamemode( ( (UserConnection) player ).getGamemode() );
|
||||
item.setPing( player.getPing() );
|
||||
packet.setItems( new PlayerListItem.Item[]
|
||||
{
|
||||
item
|
||||
} );
|
||||
BungeeCord.getInstance().broadcast( packet );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect()
|
||||
{
|
||||
BungeeCord.getInstance().broadcast( new PlayerListItem( getPlayer().getDisplayName(), false, (short) 9999 ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onListUpdate(String name, boolean online, int ping)
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction( PlayerListItem.Action.REMOVE_PLAYER );
|
||||
PlayerListItem.Item item = new PlayerListItem.Item();
|
||||
item.setUuid( player.getUniqueId() );
|
||||
item.setUsername( player.getName() );
|
||||
packet.setItems( new PlayerListItem.Item[]
|
||||
{
|
||||
return false;
|
||||
item
|
||||
} );
|
||||
BungeeCord.getInstance().broadcast( packet );
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package net.md_5.bungee.tab;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
|
||||
public class GlobalPing extends Global
|
||||
@ -10,13 +13,29 @@ public class GlobalPing extends Global
|
||||
/*========================================================================*/
|
||||
private int lastPing;
|
||||
|
||||
public GlobalPing(ProxiedPlayer player)
|
||||
{
|
||||
super( player );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPingChange(int ping)
|
||||
{
|
||||
if ( ping - PING_THRESHOLD > lastPing && ping + PING_THRESHOLD < lastPing )
|
||||
{
|
||||
lastPing = ping;
|
||||
BungeeCord.getInstance().broadcast( new PlayerListItem( getPlayer().getDisplayName(), true, (short) ping ) );
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction( PlayerListItem.Action.UPDATE_LATENCY );
|
||||
PlayerListItem.Item item = new PlayerListItem.Item();
|
||||
item.setUuid( player.getUniqueId() );
|
||||
item.setUsername( player.getName() );
|
||||
item.setDisplayName( ComponentSerializer.toString( TextComponent.fromLegacyText( player.getDisplayName() ) ) );
|
||||
item.setPing( player.getPing() );
|
||||
packet.setItems( new PlayerListItem.Item[]
|
||||
{
|
||||
item
|
||||
} );
|
||||
BungeeCord.getInstance().broadcast( packet );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,38 +2,105 @@ package net.md_5.bungee.tab;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import net.md_5.bungee.api.tab.TabListAdapter;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
|
||||
public class ServerUnique extends TabListAdapter
|
||||
public class ServerUnique extends TabList
|
||||
{
|
||||
|
||||
private final Collection<String> usernames = new HashSet<>();
|
||||
private final Collection<UUID> uuids = new HashSet<>();
|
||||
private final Collection<String> usernames = new HashSet<>(); // Support for <=1.7.9
|
||||
|
||||
public ServerUnique(ProxiedPlayer player)
|
||||
{
|
||||
super( player );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(PlayerListItem playerListItem)
|
||||
{
|
||||
for ( PlayerListItem.Item item : playerListItem.getItems() )
|
||||
{
|
||||
if ( playerListItem.getAction() == PlayerListItem.Action.ADD_PLAYER )
|
||||
{
|
||||
if ( item.getUuid() != null )
|
||||
{
|
||||
uuids.add( item.getUuid() );
|
||||
} else
|
||||
{
|
||||
usernames.add( item.getUsername() );
|
||||
}
|
||||
} else if ( playerListItem.getAction() == PlayerListItem.Action.REMOVE_PLAYER )
|
||||
{
|
||||
if ( item.getUuid() != null )
|
||||
{
|
||||
uuids.remove( item.getUuid() );
|
||||
} else
|
||||
{
|
||||
usernames.remove( item.getUsername() );
|
||||
}
|
||||
}
|
||||
}
|
||||
player.unsafe().sendPacket( playerListItem );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPingChange(int ping)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange()
|
||||
{
|
||||
synchronized ( usernames )
|
||||
PlayerListItem packet = new PlayerListItem();
|
||||
packet.setAction( PlayerListItem.Action.REMOVE_PLAYER );
|
||||
PlayerListItem.Item[] items = new PlayerListItem.Item[ uuids.size() + usernames.size() ];
|
||||
int i = 0;
|
||||
for ( UUID uuid : uuids )
|
||||
{
|
||||
PlayerListItem.Item item = items[i++] = new PlayerListItem.Item();
|
||||
item.setUuid( uuid );
|
||||
}
|
||||
for ( String username : usernames )
|
||||
{
|
||||
getPlayer().unsafe().sendPacket( new PlayerListItem( username, false, (short) 9999 ) );
|
||||
PlayerListItem.Item item = items[i++] = new PlayerListItem.Item();
|
||||
item.setUsername( username );
|
||||
item.setDisplayName( username );
|
||||
}
|
||||
packet.setItems( items );
|
||||
if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_SNAPSHOT )
|
||||
{
|
||||
player.unsafe().sendPacket( packet );
|
||||
} else
|
||||
{
|
||||
// Split up the packet
|
||||
for ( PlayerListItem.Item item : packet.getItems() )
|
||||
{
|
||||
PlayerListItem p2 = new PlayerListItem();
|
||||
p2.setAction( packet.getAction() );
|
||||
PlayerListItem.Item[] it = new PlayerListItem.Item[ 1 ];
|
||||
it[0] = item;
|
||||
p2.setItems( it );
|
||||
player.unsafe().sendPacket( p2 );
|
||||
}
|
||||
}
|
||||
uuids.clear();
|
||||
usernames.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onListUpdate(String name, boolean online, int ping)
|
||||
public void onConnect()
|
||||
{
|
||||
if ( online )
|
||||
{
|
||||
usernames.add( name );
|
||||
} else
|
||||
{
|
||||
usernames.remove( name );
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
@Override
|
||||
public void onDisconnect()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
59
proxy/src/main/java/net/md_5/bungee/tab/TabList.java
Normal file
59
proxy/src/main/java/net/md_5/bungee/tab/TabList.java
Normal file
@ -0,0 +1,59 @@
|
||||
package net.md_5.bungee.tab;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.connection.LoginResult;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class TabList
|
||||
{
|
||||
|
||||
protected final ProxiedPlayer player;
|
||||
|
||||
public abstract void onUpdate(PlayerListItem playerListItem);
|
||||
|
||||
public abstract void onPingChange(int ping);
|
||||
|
||||
public abstract void onServerChange();
|
||||
|
||||
public abstract void onConnect();
|
||||
|
||||
public abstract void onDisconnect();
|
||||
|
||||
public static PlayerListItem rewrite(PlayerListItem playerListItem)
|
||||
{
|
||||
for ( PlayerListItem.Item item : playerListItem.getItems() )
|
||||
{
|
||||
if ( item.getUuid() == null ) // Old style ping
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UserConnection player = BungeeCord.getInstance().getPlayerByOfflineUUID( item.getUuid() );
|
||||
if ( player != null )
|
||||
{
|
||||
item.setUuid( player.getUniqueId() );
|
||||
LoginResult loginResult = player.getPendingConnection().getLoginProfile();
|
||||
String[][] props = new String[ loginResult.getProperties().length ][];
|
||||
for ( int i = 0; i < props.length; i++ )
|
||||
{
|
||||
props[ i] = new String[]
|
||||
{
|
||||
loginResult.getProperties()[i].getName(),
|
||||
loginResult.getProperties()[i].getValue(),
|
||||
loginResult.getProperties()[i].getSignature()
|
||||
};
|
||||
}
|
||||
item.setProperties( props );
|
||||
if ( playerListItem.getAction() == PlayerListItem.Action.ADD_PLAYER || playerListItem.getAction() == PlayerListItem.Action.UPDATE_GAMEMODE )
|
||||
{
|
||||
player.setGamemode( item.getGamemode() );
|
||||
}
|
||||
player.setPing( player.getPing() );
|
||||
}
|
||||
}
|
||||
return playerListItem;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user