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
}
}