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
b90791d41f
commit
77be5eee80
@ -137,6 +137,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
private boolean transferred;
|
private boolean transferred;
|
||||||
private UserConnection userCon;
|
private UserConnection userCon;
|
||||||
|
|
||||||
|
@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
|
||||||
{
|
{
|
||||||
@ -448,6 +457,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 )
|
||||||
@ -456,14 +466,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>()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -480,6 +482,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;
|
||||||
@ -534,8 +546,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;
|
||||||
}
|
}
|
||||||
@ -553,10 +565,25 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
|
|
||||||
private void finish()
|
private void finish()
|
||||||
{
|
{
|
||||||
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rewriteId = ( bungee.config.isIpForward() ) ? uniqueId : offlineId;
|
rewriteId = ( bungee.config.isIpForward() ) ? uniqueId : offlineId;
|
||||||
|
|
||||||
@ -764,6 +791,59 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateOfflineId()
|
||||||
|
{
|
||||||
|
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getVersion()
|
public int getVersion()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user