Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account. The UUID and player name is altered to avoid collision with other player: UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx - The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C). - The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2. - The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index. Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
This commit is contained in:
parent
78cee7d86c
commit
ad3eb412ff
@ -112,6 +112,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
@Getter
|
@Getter
|
||||||
private String extraDataInHandshake = "";
|
private String extraDataInHandshake = "";
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private boolean duplication = false;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String realName = null;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private UUID realId = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldHandle(PacketWrapper packet) throws Exception
|
public boolean shouldHandle(PacketWrapper packet) throws Exception
|
||||||
{
|
{
|
||||||
@ -408,6 +417,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.loginRequest = loginRequest;
|
this.loginRequest = loginRequest;
|
||||||
|
setName( realName = loginRequest.getData() );
|
||||||
|
|
||||||
int limit = BungeeCord.getInstance().config.getPlayerLimit();
|
int limit = BungeeCord.getInstance().config.getPlayerLimit();
|
||||||
if ( limit > 0 && bungee.getOnlineCount() >= limit )
|
if ( limit > 0 && bungee.getOnlineCount() >= limit )
|
||||||
@ -416,14 +426,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If offline mode and they are already on, don't allow connect
|
|
||||||
// We can just check by UUID here as names are based on UUID
|
|
||||||
if ( !isOnlineMode() && bungee.getPlayer( getUniqueId() ) != null )
|
|
||||||
{
|
|
||||||
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>()
|
Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -440,6 +442,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ( !realName.equals( name ) )
|
||||||
|
{
|
||||||
|
// Floodgate changes the name attribute with reflexion
|
||||||
|
setName( realName = name );
|
||||||
|
}
|
||||||
|
if ( uniqueId != null )
|
||||||
|
{
|
||||||
|
// if plugin called setUniqueId()
|
||||||
|
realId = uniqueId;
|
||||||
|
}
|
||||||
if ( onlineMode )
|
if ( onlineMode )
|
||||||
{
|
{
|
||||||
thisState = State.ENCRYPT;
|
thisState = State.ENCRYPT;
|
||||||
@ -494,8 +506,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
if ( obj != null && obj.getId() != null )
|
if ( obj != null && obj.getId() != null )
|
||||||
{
|
{
|
||||||
loginProfile = obj;
|
loginProfile = obj;
|
||||||
name = obj.getName();
|
setName( realName = obj.getName() );
|
||||||
uniqueId = Util.getUUID( obj.getId() );
|
uniqueId = realId = Util.getUUID( obj.getId() );
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -513,10 +525,25 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
|
|
||||||
private void finish()
|
private void finish()
|
||||||
{
|
{
|
||||||
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
|
if ( uniqueId == null ) // offline mode and no plugin used setUniqueId()
|
||||||
if ( uniqueId == null )
|
|
||||||
{
|
{
|
||||||
uniqueId = offlineId;
|
uniqueId = realId = offlineId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this point, player is either authenticated by Mojang (online mode),
|
||||||
|
* by a plugin (Floodgate ?) or the offline id is set.
|
||||||
|
*/
|
||||||
|
ProxiedPlayer existingPlayer = bungee.getPlayer( uniqueId );
|
||||||
|
if ( existingPlayer != null && existingPlayer.hasPermission( "bungeecord.multiple_connect" ) )
|
||||||
|
{
|
||||||
|
UUID newId = generateDuplicatedId( uniqueId );
|
||||||
|
if ( !uniqueId.equals( newId ) )
|
||||||
|
{
|
||||||
|
uniqueId = newId;
|
||||||
|
setName( name + "." + getDuplicationIndex( newId ) );
|
||||||
|
duplication = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( BungeeCord.getInstance().config.isEnforceSecureProfile() )
|
if ( BungeeCord.getInstance().config.isEnforceSecureProfile() )
|
||||||
@ -670,6 +697,54 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData();
|
return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
if ( loginRequest != null )
|
||||||
|
{
|
||||||
|
loginRequest.setData( name ); // name transmitted to Spigot server
|
||||||
|
}
|
||||||
|
updateOfflineId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID generateDuplicatedId(UUID base)
|
||||||
|
{
|
||||||
|
// UUID version: offline = 3 ; Java online mode = 4 ; Floodgate xUID = 0 (and must be kept 0)
|
||||||
|
// UUID variant: offline = 0xx ; Java online mode = 10x ; Floodgate xUID = xxx
|
||||||
|
if ( base.version() == 0 )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Floodgate’s xUID converted to UUID are not supported
|
||||||
|
* because it requires the 64 MSBs to be 0 (or Floodgate API would not
|
||||||
|
* recognize a Bedrock account) and we cannot modify the 64 LSBs
|
||||||
|
* without risking a collision with the xUID of another Bedrock account
|
||||||
|
*/
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
long MSB = base.getMostSignificantBits();
|
||||||
|
long LSB = base.getLeastSignificantBits();
|
||||||
|
|
||||||
|
MSB &= 0xFFFFFFFF_FFFF_70FFL; // reset bits we need
|
||||||
|
MSB |= 0x00000000_0000_8000L; // set version to + 8 the current version
|
||||||
|
|
||||||
|
for ( int i = 1; i <= 9; i++ )
|
||||||
|
{
|
||||||
|
long newMSB = MSB | i << 8;
|
||||||
|
UUID newUUID = new UUID( newMSB, LSB );
|
||||||
|
if ( bungee.getPlayer( newUUID ) != null )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return newUUID;
|
||||||
|
}
|
||||||
|
return base; // there are too many duplicated connections for this player
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getDuplicationIndex(UUID duplicatedId)
|
||||||
|
{
|
||||||
|
return (int) ( duplicatedId.getMostSignificantBits() >> 8 ) & 0xF;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getVersion()
|
public int getVersion()
|
||||||
{
|
{
|
||||||
@ -709,6 +784,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
this.uniqueId = uuid;
|
this.uniqueId = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateOfflineId()
|
||||||
|
{
|
||||||
|
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUUID()
|
public String getUUID()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user