Add support for 15w33c and multiple fallback servers

This commit is contained in:
Thinkofdeath
2016-03-01 09:13:13 +11:00
committed by md_5
parent dfaa687f71
commit 12a7b7afc3
13 changed files with 306 additions and 93 deletions

View File

@@ -1,6 +1,7 @@
package net.md_5.bungee;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -575,7 +576,7 @@ public class BungeeCord extends ProxyServer
@Override
public String getGameVersion()
{
return "1.8";
return Joiner.on(", ").join(ProtocolConstants.SUPPORTED_VERSIONS);
}
@Override

View File

@@ -4,6 +4,8 @@ import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import lombok.Getter;
@@ -255,12 +257,24 @@ public class ServerConnector extends PacketHandler
@Override
public void handle(Kick kick) throws Exception
{
ServerInfo def = bungee.getServerInfo( user.getPendingConnection().getListener().getFallbackServer() );
user.setLastServerJoined(user.getLastServerJoined() + 1);
String serverName = "";
List<String> servers = user.getPendingConnection().getListener().getServerPriority();
if ( user.getLastServerJoined() < servers.size() ) {
serverName = servers.get( user.getLastServerJoined() );
}
ServerInfo def = ProxyServer.getInstance().getServers().get( serverName );
if ( Objects.equal( target, def ) )
{
def = null;
}
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( user, target, ComponentSerializer.parse( kick.getMessage() ), def, ServerKickEvent.State.CONNECTING ) );
ServerKickEvent event = new ServerKickEvent(user, target, ComponentSerializer.parse(kick.getMessage()), def, ServerKickEvent.State.CONNECTING);
if ( event.getKickReason().toLowerCase().contains( "outdated" ) && def != null )
{
// Pre cancel the event if we are going to try another server
event.setCancelled( true );
}
bungee.getPluginManager().callEvent( event );
if ( event.isCancelled() && event.getCancelServer() != null )
{
user.connect( event.getCancelServer() );
@@ -314,11 +328,6 @@ public class ServerConnector extends PacketHandler
if ( pluginMessage.getTag().equals( ForgeConstants.FML_HANDSHAKE_TAG ) || pluginMessage.getTag().equals( ForgeConstants.FORGE_REGISTER ) )
{
this.handshakeHandler.handle( pluginMessage );
if ( user.getForgeClientHandler().checkUserOutdated() )
{
ch.close();
user.getPendingConnects().remove( target );
}
// We send the message as part of the handler, so don't send it here.
throw CancelSendSignal.INSTANCE;

View File

@@ -14,6 +14,7 @@ import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
@@ -55,6 +56,8 @@ import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
import net.md_5.bungee.protocol.packet.PluginMessage;
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;
@@ -102,6 +105,10 @@ public final class UserConnection implements ProxiedPlayer
private int gamemode;
@Getter
private int compressionThreshold = -1;
// Used for trying multiple servers in order
@Getter
@Setter
private int lastServerJoined = 0;
/*========================================================================*/
private final Collection<String> groups = new CaseInsensitiveSet();
private final Collection<String> permissions = new CaseInsensitiveSet();
@@ -145,20 +152,18 @@ public final class UserConnection implements ProxiedPlayer
this.displayName = name;
// Blame Mojang for this one
/*switch ( getPendingConnection().getListener().getTabListType() )
{
case "GLOBAL":
tabListHandler = new Global( this );
break;
case "SERVER":
tabListHandler = new ServerUnique( this );
break;
default:
tabListHandler = new GlobalPing( this );
break;
}*/
tabListHandler = new ServerUnique( this );
switch ( getPendingConnection().getListener().getTabListType() )
{
case "GLOBAL":
tabListHandler = new Global( this );
break;
case "SERVER":
tabListHandler = new ServerUnique( this );
break;
default:
tabListHandler = new GlobalPing( this );
break;
}
Collection<String> g = bungee.getConfigurationAdapter().getGroups( name );
g.addAll( bungee.getConfigurationAdapter().getGroups( getUniqueId().toString() ) );
@@ -187,7 +192,7 @@ public final class UserConnection implements ProxiedPlayer
@Override
public void setDisplayName(String name)
{
Preconditions.checkNotNull( name, "displayName" );
Preconditions.checkNotNull(name, "displayName");
Preconditions.checkArgument( name.length() <= 16, "Display name cannot be longer than 16 characters" );
displayName = name;
}
@@ -267,9 +272,16 @@ public final class UserConnection implements ProxiedPlayer
if ( !future.isSuccess() )
{
future.channel().close();
pendingConnects.remove( target );
pendingConnects.remove(target);
ServerInfo def = ProxyServer.getInstance().getServers().get( getPendingConnection().getListener().getFallbackServer() );
lastServerJoined++;
String serverName = "";
List<String> servers = getPendingConnection().getListener().getServerPriority();
if ( lastServerJoined < servers.size() ) {
serverName = servers.get( lastServerJoined );
}
ServerInfo def = ProxyServer.getInstance().getServers().get( serverName );
if ( retry && target != def && ( getServer() == null || def != getServer().getInfo() ) )
{
sendMessage( bungee.getTranslation( "fallback_lobby" ) );
@@ -281,6 +293,8 @@ public final class UserConnection implements ProxiedPlayer
{
sendMessage( bungee.getTranslation( "fallback_kick", future.cause().getClass().getName() ) );
}
} else {
lastServerJoined = 0;
}
}
};

View File

@@ -27,6 +27,8 @@ public abstract class EntityMap
{
case ProtocolConstants.MINECRAFT_1_8:
return EntityMap_1_8.INSTANCE;
case ProtocolConstants.MINECRAFT_SNAPSHOT:
return EntityMap_1_SNAPSHOT.INSTANCE;
}
throw new RuntimeException( "Version " + version + " has no entity map" );
}

View File

@@ -97,28 +97,12 @@ class EntityMap_1_8 extends EntityMap
packet.skipBytes( 14 );
int position = packet.readerIndex();
int readId = packet.readInt();
int changedId = -1;
if ( readId == oldId )
{
packet.setInt( position, newId );
changedId = newId;
} else if ( readId == newId )
{
packet.setInt( position, oldId );
changedId = oldId;
}
if ( changedId != -1 )
{
if ( changedId == 0 && readId != 0 )
{ // Trim off the extra data
packet.readerIndex( readerIndex );
packet.writerIndex( packet.readableBytes() - 6 );
} else if ( changedId != 0 && readId == 0 )
{ // Add on the extra data
packet.readerIndex( readerIndex );
packet.capacity( packet.readableBytes() + 6 );
packet.writerIndex( packet.readableBytes() + 6 );
}
}
}
} else if ( packetId == 0x0C /* Spawn Player */ )

View File

@@ -0,0 +1,181 @@
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_SNAPSHOT extends EntityMap
{
static final EntityMap_SNAPSHOT INSTANCE = new EntityMap_SNAPSHOT();
EntityMap_SNAPSHOT()
{
addRewrite( 0x04, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Equipment
addRewrite( 0x0A, ProtocolConstants.Direction.TO_CLIENT, true ); // Use bed
addRewrite( 0x0B, ProtocolConstants.Direction.TO_CLIENT, true ); // Animation
addRewrite( 0x0C, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Player
addRewrite( 0x0D, ProtocolConstants.Direction.TO_CLIENT, true ); // Collect Item
addRewrite( 0x0E, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Object
addRewrite( 0x0F, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Mob
addRewrite( 0x10, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Painting
addRewrite( 0x11, ProtocolConstants.Direction.TO_CLIENT, true ); // Spawn Experience Orb
addRewrite( 0x12, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Velocity
addRewrite( 0x14, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity
addRewrite( 0x15, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Relative Move
addRewrite( 0x16, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Look
addRewrite( 0x17, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Look and Relative Move
addRewrite( 0x18, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Teleport
addRewrite( 0x19, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Head Look
addRewrite( 0x1A, ProtocolConstants.Direction.TO_CLIENT, false ); // Entity Status
addRewrite( 0x1B, ProtocolConstants.Direction.TO_CLIENT, false ); // Attach Entity
addRewrite( 0x1C, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Metadata
addRewrite( 0x1D, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Effect
addRewrite( 0x1E, ProtocolConstants.Direction.TO_CLIENT, true ); // Remove Entity Effect
addRewrite( 0x20, ProtocolConstants.Direction.TO_CLIENT, true ); // Entity Properties
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( 0x0C, ProtocolConstants.Direction.TO_SERVER, true ); // Entity Action
}
@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;
if ( packetId == 0x0D /* Collect Item */ )
{
DefinedPacket.readVarInt( packet );
rewriteVarInt( packet, oldId, newId, packet.readerIndex() );
} else if ( packetId == 0x1B /* Attach Entity */ )
{
rewriteInt( packet, oldId, newId, readerIndex + packetIdLength + 4 );
} else if ( packetId == 0x13 /* Destroy Entities */ )
{
int count = DefinedPacket.readVarInt( packet );
int[] ids = new int[ count ];
for ( int i = 0; i < count; i++ )
{
ids[ i ] = DefinedPacket.readVarInt( packet );
}
packet.readerIndex( readerIndex + packetIdLength );
packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeVarInt( count, packet );
for ( int id : ids )
{
if ( id == oldId )
{
id = newId;
} else if ( id == newId )
{
id = oldId;
}
DefinedPacket.writeVarInt( id, packet );
}
} else if ( packetId == 0x0E /* Spawn Object */ )
{
DefinedPacket.readVarInt( packet );
int type = packet.readUnsignedByte();
if ( type == 60 || type == 90 )
{
packet.skipBytes( 14 );
int position = packet.readerIndex();
int readId = packet.readInt();
int changedId = -1;
if ( readId == oldId )
{
packet.setInt( position, newId );
changedId = newId;
} else if ( readId == newId )
{
packet.setInt( position, oldId );
changedId = oldId;
}
if ( changedId != -1 )
{
if ( changedId == 0 && readId != 0 )
{ // Trim off the extra data
packet.readerIndex( readerIndex );
packet.writerIndex( packet.readableBytes() - 6 );
} else if ( changedId != 0 && readId == 0 )
{ // Add on the extra data
packet.readerIndex( readerIndex );
packet.capacity( packet.readableBytes() + 6 );
packet.writerIndex( packet.readableBytes() + 6 );
}
}
}
} else if ( packetId == 0x0C /* Spawn Player */ )
{
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 );
}
} else if ( packetId == 0x42 /* Combat Event */ )
{
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() );
}
}
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 == 0x19 /* Spectate */ && !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 );
}
}

View File

@@ -21,10 +21,6 @@ public class ForgeClientHandler
@NonNull
private final UserConnection con;
@Getter
@Setter(AccessLevel.PACKAGE)
private boolean forgeOutdated = false;
/**
* The users' mod list.
*/
@@ -160,28 +156,4 @@ public class ForgeClientHandler
{
return fmlTokenInHandshake || clientModList != null;
}
/**
* Checks to see if a user is using an outdated FML build, and takes
* appropriate action on the User side. This should only be called during a
* server connection, by the ServerConnector
*
* @return <code>true</code> if the user's FML build is outdated, otherwise
* <code>false</code>
*/
public boolean checkUserOutdated()
{
if ( forgeOutdated )
{
if ( con.isDimensionChange() )
{
con.disconnect( BungeeCord.getInstance().getTranslation( "connect_kick_outdated_forge" ) );
} else
{
con.sendMessage( BungeeCord.getInstance().getTranslation( "connect_kick_outdated_forge" ) );
}
}
return forgeOutdated;
}
}

View File

@@ -86,17 +86,6 @@ enum ForgeClientHandshakeState implements IForgeClientPacketHandler<ForgeClientH
// Once we've done it, no point doing it again.
Map<String, String> clientModList = ForgeUtils.readModList( message );
con.getForgeClientHandler().setClientModList( clientModList );
// Get the version from the mod list.
int buildNumber = ForgeUtils.getFmlBuildNumber( clientModList );
// If we get 0, we're probably using a testing build, so let it though. Otherwise, check the build number.
if ( buildNumber < ForgeConstants.FML_MIN_BUILD_VERSION && buildNumber != 0 )
{
// Mark the user as an old Forge user. This will then cause any Forge ServerConnectors to cancel any
// connections to it.
con.getForgeClientHandler().setForgeOutdated( true );
}
}
return WAITINGSERVERDATA;