几天来,我一直在尝试如何检测玩家的帐户在离线模式下是否通过了Mojang身份验证。
我为什么要这样做?
当前,我有一个基本的管理系统,该系统包括检查玩家的昵称是否存在于mojang数据库中,是否将setOnlineMode设置为true,否则将其设置为false。 系统允许显示玩家的皮肤和他的UUID,但是问题是,如果认为脱机的玩家购买了具有相同假名的Premium帐户,则他没有皮肤或真实的UUID,因为setOnlineMode设置为false防止损失进度。 我的目标是创建一个系统,该系统可检测到离线用户刚刚使用经过身份验证的Minecraft帐户登录,以便服务器可以向其提供自动将其进度转移到新的真实UUID的信息。
我做了一些研究,例如尝试here,我删除了在线模式条件以允许检查播放器是否已通过身份验证,然后here如果播放器无效,则删除了断开连接。这给了我一个奇妙的错误。
13:13:31 [GRAVE] [Arbi13_]-> UpstreamBridge-遇到异常 io.netty.handler.codec.EncoderException:java.lang.IllegalArgumentException:在阶段GAME中,方向为TO_CLIENT的数据包类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) 位于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:在阶段GAME中,方向为TO_CLIENT的数据包类net.md_5.bungee.protocol.packet.SetCompression无法获取ID。 在com.google.common.base.Preconditions.checkArgument(Preconditions.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个
@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 );
}
答案 0 :(得分:0)
我认为这是不可能的,因为 Minecraft 没有交换会话细节。我知道运行第二个代理的服务器为高级用户启用了在线模式,以处理导致“后面”相同 bukkit 服务器的会话详细信息。