diff --git a/src/main/java/baritone/bot/IBaritoneUser.java b/src/main/java/baritone/bot/IBaritoneUser.java index d167a2d2..47507922 100644 --- a/src/main/java/baritone/bot/IBaritoneUser.java +++ b/src/main/java/baritone/bot/IBaritoneUser.java @@ -20,6 +20,7 @@ package baritone.bot; import baritone.bot.entity.EntityBot; import net.minecraft.client.entity.EntityOtherPlayerMP; import net.minecraft.network.NetworkManager; +import net.minecraft.util.Session; import net.minecraft.world.World; import javax.annotation.Nullable; @@ -47,4 +48,12 @@ public interface IBaritoneUser { * @return The remote entity for this bot */ EntityOtherPlayerMP getRemoteEntity(); + + /** + * Returns the user login session. Should never be {@code null}, as this should be set when the + * user is constructed. + * + * @return The bot's login session + */ + Session getSession(); } diff --git a/src/main/java/baritone/bot/handler/BotNetHandlerLoginClient.java b/src/main/java/baritone/bot/handler/BotNetHandlerLoginClient.java new file mode 100644 index 00000000..85cc7a6e --- /dev/null +++ b/src/main/java/baritone/bot/handler/BotNetHandlerLoginClient.java @@ -0,0 +1,118 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.bot.handler; + +import baritone.bot.IBaritoneUser; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.exceptions.AuthenticationException; +import com.mojang.authlib.exceptions.AuthenticationUnavailableException; +import com.mojang.authlib.exceptions.InvalidCredentialsException; +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.NetHandlerLoginClient; +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.login.client.CPacketEncryptionResponse; +import net.minecraft.network.login.server.SPacketEncryptionRequest; +import net.minecraft.network.login.server.SPacketLoginSuccess; +import net.minecraft.util.CryptManager; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; + +import javax.annotation.Nonnull; +import javax.crypto.SecretKey; +import java.math.BigInteger; +import java.security.PublicKey; + +/** + * Handles the login stage when connecting to a server. + * + * @author Brady + * @since 10/29/2018 + */ +public class BotNetHandlerLoginClient extends NetHandlerLoginClient { + + /** + * The {@link NetworkManager} that is managing the connection with the server. + */ + private final NetworkManager networkManager; + + /** + * The {@link Minecraft} game instance + */ + private final Minecraft mc; + + /** + * The bot of this connection + */ + private final IBaritoneUser user; + + public BotNetHandlerLoginClient(NetworkManager networkManager, IBaritoneUser user) { + super(networkManager, Minecraft.getMinecraft(), null); + this.networkManager = networkManager; + this.mc = Minecraft.getMinecraft(); + this.user = user; + } + + @Override + public void handleEncryptionRequest(SPacketEncryptionRequest packetIn) { + SecretKey secretkey = CryptManager.createNewSharedKey(); + PublicKey publicKey = packetIn.getPublicKey(); + + // Setup joinServer payload info + GameProfile profile = this.user.getSession().getProfile(); + String authenticationToken = this.user.getSession().getToken(); + String serverId = new BigInteger(CryptManager.getServerIdHash(packetIn.getServerId(), publicKey, secretkey)).toString(16); + + if (this.mc.getCurrentServerData() != null && this.mc.getCurrentServerData().isOnLAN()) { + try { + this.mc.getSessionService().joinServer(profile, authenticationToken, serverId); + } catch (AuthenticationException e) { + // Couldn't connect to auth servers but will continue to join LAN + } + } else { + try { + this.mc.getSessionService().joinServer(profile, authenticationToken, serverId); + } catch (AuthenticationUnavailableException e) { + this.networkManager.closeChannel(new TextComponentTranslation("disconnect.loginFailedInfo", new TextComponentTranslation("disconnect.loginFailedInfo.serversUnavailable"))); + return; + } catch (InvalidCredentialsException e) { + this.networkManager.closeChannel(new TextComponentTranslation("disconnect.loginFailedInfo", new TextComponentTranslation("disconnect.loginFailedInfo.invalidSession"))); + return; + } catch (AuthenticationException e) { + this.networkManager.closeChannel(new TextComponentTranslation("disconnect.loginFailedInfo", e.getMessage())); + return; + } + } + + // noinspection unchecked + this.networkManager.sendPacket(new CPacketEncryptionResponse(secretkey, publicKey, packetIn.getVerifyToken()), + future -> BotNetHandlerLoginClient.this.networkManager.enableEncryption(secretkey)); + } + + @Override + public void handleLoginSuccess(SPacketLoginSuccess packetIn) { + this.networkManager.setConnectionState(EnumConnectionState.PLAY); + this.networkManager.setNetHandler(new BotNetHandlerPlayClient(this.networkManager, this.user, Minecraft.getMinecraft(), packetIn.getProfile())); + } + + @Override + public void onDisconnect(@Nonnull ITextComponent reason) { + // TODO Notify the bot manager that we are no longer connected + // It's important that we don't call the superclass method because that would mess up GUIs and make us upset + } +} diff --git a/src/main/java/baritone/bot/net/BotNetHandlerPlayClient.java b/src/main/java/baritone/bot/handler/BotNetHandlerPlayClient.java similarity index 95% rename from src/main/java/baritone/bot/net/BotNetHandlerPlayClient.java rename to src/main/java/baritone/bot/handler/BotNetHandlerPlayClient.java index 02fa54bb..05cd687b 100644 --- a/src/main/java/baritone/bot/net/BotNetHandlerPlayClient.java +++ b/src/main/java/baritone/bot/handler/BotNetHandlerPlayClient.java @@ -15,12 +15,15 @@ * along with Baritone. If not, see . */ -package baritone.bot.net; +package baritone.bot.handler; import baritone.bot.IBaritoneUser; import baritone.bot.entity.EntityBot; +import com.mojang.authlib.GameProfile; import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.InventoryPlayer; @@ -33,7 +36,6 @@ import net.minecraft.network.play.client.CPacketResourcePackStatus; import net.minecraft.network.play.server.*; import net.minecraft.util.IThreadListener; import net.minecraft.util.text.ITextComponent; -import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -43,16 +45,23 @@ import javax.annotation.Nonnull; // - For other things, we'll actually need the system /** + * This class would effectively operate the same if we directly implemented {@link INetHandlerPlayClient}, + * however, the {@link EntityPlayerSP} constructor requires an actual implementation of + * {@link NetHandlerPlayClient} in order to access the {@link GameProfile}. + * * @author Brady * @since 10/22/2018 */ -public class BotNetHandlerPlayClient implements INetHandlerPlayClient { +public class BotNetHandlerPlayClient extends NetHandlerPlayClient { + /** + * The {@link NetworkManager} that is managing the connection with the server. + */ private final NetworkManager networkManager; /** * This is the {@link Minecraft} game instance, however, to prevent unwanted references - * to the game instance fields, we refer to it as a {@link IThreadListener} + * to the game instance fields, we refer to it as a {@link IThreadListener}. */ private final IThreadListener client; @@ -71,7 +80,9 @@ public class BotNetHandlerPlayClient implements INetHandlerPlayClient { */ private WorldClient world; - public BotNetHandlerPlayClient(NetworkManager networkManager, IThreadListener client, IBaritoneUser user) { + public BotNetHandlerPlayClient(NetworkManager networkManager, IBaritoneUser user, Minecraft client, GameProfile profile) { + // noinspection ConstantConditions + super(client, null, networkManager, profile); this.networkManager = networkManager; this.client = client; this.user = user; @@ -485,6 +496,6 @@ public class BotNetHandlerPlayClient implements INetHandlerPlayClient { @Override public void onDisconnect(@Nonnull ITextComponent reason) { - /* Unload the world and notify the bot manager that we are no longer connected */ + // TODO Unload the world and notify the bot manager that we are no longer connected } }