Java BungeeCord-在脱机模式下检测到经过身份验证的播放器

Java BungeeCord-在脱机模式下检测到经过身份验证的播放器,java,minecraft,bukkit,bungeecord,Java,Minecraft,Bukkit,Bungeecord,我已经尝试了几天如何检测一个玩家的帐户是否在离线模式下被验证为Mojang 我为什么要这么做 目前,我有一个基本的管理系统,包括检查mojang数据库中是否存在玩家的昵称,是否有setOnlineMode设置为true,否则设置为false。 系统允许显示玩家的皮肤和UUID,但问题是,如果玩家考虑离线购买具有相同笔名的高级帐户,则他没有皮肤或真实UUID,因为setOnlineMode设置为false以防止其进度损失。 我的目标是开发一个系统,检测离线用户刚刚使用经过身份验证的minecraf

我已经尝试了几天如何检测一个玩家的帐户是否在离线模式下被验证为Mojang

我为什么要这么做

目前,我有一个基本的管理系统,包括检查mojang数据库中是否存在玩家的昵称,是否有setOnlineMode设置为true,否则设置为false。 系统允许显示玩家的皮肤和UUID,但问题是,如果玩家考虑离线购买具有相同笔名的高级帐户,则他没有皮肤或真实UUID,因为setOnlineMode设置为false以防止其进度损失。 我的目标是开发一个系统,检测离线用户刚刚使用经过身份验证的minecraft帐户登录,以便服务器能够自动将其进度传输到新的真实UUID

我做了一些研究,例如,我删除了onlinemode条件,以允许检查播放器是否经过身份验证,然后如果播放器无效,我删除了断开连接。这给了我一个很大的错误

13:13:31 [GRAVE] [Arbi13_] -> UpstreamBridge - encountered exception io.netty.handler.codec.EncoderException: java.lang.IllegalArgumentException: Cannot get ID for packet class net.md_5.bungee.protocol.packet.SetCompression in phase GAME with direction TO_CLIENT at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:125) at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738) at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:801) at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814) at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794) at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1066) at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:305) at net.md_5.bungee.netty.ChannelWrapper.write(ChannelWrapper.java:60) at net.md_5.bungee.UserConnection$1.sendPacket(UserConnection.java:148) at net.md_5.bungee.UserConnection.setCompressionThreshold(UserConnection.java:697) at net.md_5.bungee.connection.InitialHandler$6$1.run(InitialHandler.java:523) at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:326) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.IllegalArgumentException: Cannot get ID for packet class net.md_5.bungee.protocol.packet.SetCompression in phase GAME with direction TO_CLIENT at com.google.common.base.Preconditions.checkArgument(Preconditions.java:399) at net.md_5.bungee.protocol.Protocol$DirectionData.getId(Protocol.java:462) at net.md_5.bungee.protocol.MinecraftEncoder.encode(MinecraftEncoder.java:23) at net.md_5.bungee.protocol.MinecraftEncoder.encode(MinecraftEncoder.java:9) at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:107) ... 15 more 13:13:31[GRAVE][Arbi13]->UpstreamBridge-遇到异常io.netty.handler.codec.EncoderException:java.lang.IllegalArgumentException:无法获取数据包类net.md_5.bungee.protocol.packet.SetCompression的ID,并指向客户端 在io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:125) 位于io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738) 位于io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:801) 位于io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814) 位于io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794) 位于io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1066) 位于io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:305) net.md_5.bungee.netty.ChannelWrapper.write(ChannelWrapper.java:60) net.md_5.bungee.UserConnection$1.sendPacket(UserConnection.java:148) at net.md_5.bungee.UserConnection.setCompressionThreshold(UserConnection.java:697) net.md_5.bungee.connection.InitialHandler$6$1.run(InitialHandler.java:523) 位于io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) 位于io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) 位于io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:326) 位于io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897) 在java.lang.Thread.run(Thread.java:748)处,由于以下原因导致:java.lang.IllegalArgumentException:无法获取包类net.md_5.bungee.protocol.packet.SetCompression的ID,指向_客户端 位于com.google.common.base.premissions.checkArgument(premissions.java:399) net.md_5.bungee.protocol.protocol$DirectionData.getId(protocol.java:462) net.md_5.bungee.protocol.MinecraftEncoder.encode(MinecraftEncoder.java:23) net.md_5.bungee.protocol.MinecraftEncoder.encode(MinecraftEncoder.java:9) 在io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:107) ... 还有15个
@覆盖
公共无效句柄(LoginRequest LoginRequest)引发异常
{
Premissions.checkState(thisState==State.USERNAME,“不需要用户名”);
this.loginRequest=loginRequest;
如果(getName()包含(“.”)
{
断开连接(bungee.getTranslation(“name_invalid”);
返回;
}
如果(getName().length()>16)
{
断开连接(bungee.getTranslation(“name_too_long”);
返回;
}
int limit=BungeeCord.getInstance().config.getPlayerLimit();
if(limit>0&&bungee.getOnlineCount()>limit)
{
断开连接(bungee.getTranslation(“proxy_full”);
返回;
}
//如果脱机模式且它们已打开,则不允许连接
//我们可以在这里通过UUID进行检查,因为名称是基于UUID的
如果(!isOnlineMode()&&bungee.getPlayer(getUniqueId())!=null)
{
断开连接(bungee.getTranslation(“已连接的代理”);
返回;
}
Callback Callback=new Callback()
{
@凌驾
公共作废完成(预登录结果,可丢弃错误)
{
if(result.isCancelled())
{
断开连接(result.getCancelReasonComponents());
返回;
}
if(ch.isClosed())
{
返回;
}
不安全().sendPacket(请求=EncryptionUtil.encryptRequest());
thisState=State.ENCRYPT;
}
};
//fire预登录事件
bungee.getPluginManager().callEvent(新的预登录(InitialHandler.this,callback));
}
@凌驾
公共无效句柄(最终EncryptionResponse encryptResponse)引发异常
{
Premissions.checkState(thisState==State.ENCRYPT,“不需要加密”);
SecretKey sharedKey=EncryptionUtil.getSecret(encryptResponse,request);
BungeeCipher decrypt=EncryptionUtil.getCipher(false,sharedKey);
ch.addBefore(PipelineUtils.FRAME_解码器、PipelineUtils.DECRYPT_处理程序、新密码解码器(DECRYPT));
BungeeCipher encrypt=EncryptionUtil.getCipher(true,sharedKey);
ch.addBefore(PipelineUtils.FRAME_PREPENDER、PipelineUtils.ENCRYPT_HANDLER、新密码编码(ENCRYPT));
字符串encName=URLEncoder.encode(InitialHandler.this.getName(),“UTF-8”);
MessageDigest sha=MessageDigest.getInstance(“sha-1”);
对于(字节[]位:新字节[][]
{
request.getServerId().getBytes(“ISO_8859_1”)、sharedKey.getEncoded()、EncryptionUtil.keys.getPu
@Override
public void handle(LoginRequest loginRequest) throws Exception
{
    Preconditions.checkState( thisState == State.USERNAME, "Not expecting USERNAME" );
    this.loginRequest = loginRequest;

    if ( getName().contains( "." ) )
    {
        disconnect( bungee.getTranslation( "name_invalid" ) );
        return;
    }

    if ( getName().length() > 16 )
    {
        disconnect( bungee.getTranslation( "name_too_long" ) );
        return;
    }

    int limit = BungeeCord.getInstance().config.getPlayerLimit();
    if ( limit > 0 && bungee.getOnlineCount() > limit )
    {
        disconnect( bungee.getTranslation( "proxy_full" ) );
        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>()
    {

        @Override
        public void done(PreLoginEvent result, Throwable error)
        {
            if ( result.isCancelled() )
            {
                disconnect( result.getCancelReasonComponents() );
                return;
            }
            if ( ch.isClosed() )
            {
                return;
            }
            unsafe().sendPacket( request = EncryptionUtil.encryptRequest() );
            thisState = State.ENCRYPT;
        }
    };

    // fire pre login event
    bungee.getPluginManager().callEvent( new PreLoginEvent( InitialHandler.this, callback ) );
}

@Override
public void handle(final EncryptionResponse encryptResponse) throws Exception
{
    Preconditions.checkState( thisState == State.ENCRYPT, "Not expecting ENCRYPT" );

    SecretKey sharedKey = EncryptionUtil.getSecret( encryptResponse, request );
    BungeeCipher decrypt = EncryptionUtil.getCipher( false, sharedKey );
    ch.addBefore( PipelineUtils.FRAME_DECODER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
    BungeeCipher encrypt = EncryptionUtil.getCipher( true, sharedKey );
    ch.addBefore( PipelineUtils.FRAME_PREPENDER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );

    String encName = URLEncoder.encode( InitialHandler.this.getName(), "UTF-8" );

    MessageDigest sha = MessageDigest.getInstance( "SHA-1" );
    for ( byte[] bit : new byte[][]
    {
        request.getServerId().getBytes( "ISO_8859_1" ), sharedKey.getEncoded(), EncryptionUtil.keys.getPublic().getEncoded()
    } )
    {
        sha.update( bit );
    }
    String encodedHash = URLEncoder.encode( new BigInteger( sha.digest() ).toString( 16 ), "UTF-8" );

    String preventProxy = ( ( BungeeCord.getInstance().config.isPreventProxyConnections() ) ? "&ip=" + URLEncoder.encode( getAddress().getAddress().getHostAddress(), "UTF-8" ) : "" );
    String authURL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encName + "&serverId=" + encodedHash + preventProxy;

    Callback<String> handler = new Callback<String>()
    {
        @Override
        public void done(String result, Throwable error)
        {
            if ( error == null )
            {
                LoginResult obj = BungeeCord.getInstance().gson.fromJson( result, LoginResult.class );
                if ( obj != null && obj.getId() != null )
                {
                    loginProfile = obj;
                    name = obj.getName();
                    uniqueId = Util.getUUID( obj.getId() );
                    authenticated = true;
                    finish();
                    return;


          }
            if(isOnlineMode()) {
                disconnect(bungee.getTranslation("offline_mode_player"));
                return;
            }

            finish();
            return;
        } else
        {
            disconnect( bungee.getTranslation( "mojang_fail" ) );
            bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", error );
        }
    }
};

HttpClient.get( authURL, ch.getHandle().eventLoop(), handler );
}