diff --git a/src/main/java/baritone/bot/BaritoneUser.java b/src/main/java/baritone/bot/BaritoneUser.java
index a2f3743f2..ccf49382e 100644
--- a/src/main/java/baritone/bot/BaritoneUser.java
+++ b/src/main/java/baritone/bot/BaritoneUser.java
@@ -17,7 +17,7 @@
package baritone.bot;
-import baritone.bot.entity.EntityBot;
+import baritone.bot.spec.EntityBot;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.INetHandlerPlayClient;
diff --git a/src/main/java/baritone/bot/BotWorldProvider.java b/src/main/java/baritone/bot/BotWorldProvider.java
new file mode 100644
index 000000000..87fd3522a
--- /dev/null
+++ b/src/main/java/baritone/bot/BotWorldProvider.java
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+import baritone.bot.spec.BotWorld;
+import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import net.minecraft.entity.Entity;
+import net.minecraft.world.GameType;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldSettings;
+import net.minecraft.world.WorldType;
+
+/**
+ * @author Brady
+ * @since 11/7/2018
+ */
+public class BotWorldProvider {
+
+ /**
+ * Generic world settings for a typical survival world.
+ */
+ private static final WorldSettings GENERIC_WORLD_SETTINGS = new WorldSettings(0L, GameType.SURVIVAL, true, false, WorldType.DEFAULT);
+
+ /**
+ * All of the dimensions mapped to their respective worlds.
+ */
+ private final Int2ObjectMap worlds = new Int2ObjectArrayMap<>();
+
+ /**
+ * Gets or creates the {@link BotWorld} for the specified dimension
+ *
+ * @param dimension The dimension id
+ * @return The world
+ */
+ public BotWorld getWorld(int dimension) {
+ return worlds.computeIfAbsent(dimension, this::createWorldForDim);
+ }
+
+ private BotWorld createWorldForDim(int dimension) {
+ return new BotWorld(GENERIC_WORLD_SETTINGS, dimension);
+ }
+
+ public void tick() {
+ this.worlds.forEach((dim, world) -> world.updateEntities());
+ }
+}
diff --git a/src/main/java/baritone/bot/IBaritoneUser.java b/src/main/java/baritone/bot/IBaritoneUser.java
index f420869ad..2b306c2a8 100644
--- a/src/main/java/baritone/bot/IBaritoneUser.java
+++ b/src/main/java/baritone/bot/IBaritoneUser.java
@@ -17,7 +17,7 @@
package baritone.bot;
-import baritone.bot.entity.EntityBot;
+import baritone.bot.spec.EntityBot;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetworkManager;
diff --git a/src/main/java/baritone/bot/UserManager.java b/src/main/java/baritone/bot/UserManager.java
index 2fa23f152..de4cbe7c5 100644
--- a/src/main/java/baritone/bot/UserManager.java
+++ b/src/main/java/baritone/bot/UserManager.java
@@ -19,9 +19,11 @@ package baritone.bot;
import baritone.Baritone;
import baritone.api.event.events.TickEvent;
+import baritone.api.event.events.type.EventState;
import baritone.api.event.listener.AbstractGameEventListener;
import baritone.bot.connect.ConnectionResult;
import baritone.bot.handler.BotNetHandlerLoginClient;
+import baritone.bot.spec.BotWorld;
import baritone.utils.Helper;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.multiplayer.ServerAddress;
@@ -34,7 +36,6 @@ import net.minecraft.util.Session;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -52,17 +53,24 @@ public final class UserManager implements Helper {
private final List users = new CopyOnWriteArrayList<>();
+ private final BotWorldProvider worldProvider;
+
private UserManager() {
// Setup an event listener that automatically disconnects bots when we're not in-game
Baritone.INSTANCE.registerEventListener(new AbstractGameEventListener() {
@Override
public final void onTick(TickEvent event) {
- if (event.getType() == TickEvent.Type.OUT) {
- UserManager.this.users.forEach(UserManager.this::disconnect);
+ if (event.getState() == EventState.PRE) {
+ if (event.getType() == TickEvent.Type.OUT)
+ UserManager.this.users.forEach(UserManager.this::disconnect);
+
+ UserManager.this.worldProvider.tick();
}
}
});
+
+ this.worldProvider = new BotWorldProvider();
}
/**
@@ -162,4 +170,11 @@ public final class UserManager implements Helper {
public final Optional getUserByUUID(UUID uuid) {
return uuid == null ? Optional.empty() : this.users.stream().filter(user -> user.getProfile().getId().equals(uuid)).findFirst();
}
+
+ /**
+ * @return The bot world provider
+ */
+ public final BotWorldProvider getWorldProvider() {
+ return this.worldProvider;
+ }
}
diff --git a/src/main/java/baritone/bot/handler/BotNetHandlerPlayClient.java b/src/main/java/baritone/bot/handler/BotNetHandlerPlayClient.java
index 045e7f3cb..8d5889dd7 100644
--- a/src/main/java/baritone/bot/handler/BotNetHandlerPlayClient.java
+++ b/src/main/java/baritone/bot/handler/BotNetHandlerPlayClient.java
@@ -18,18 +18,21 @@
package baritone.bot.handler;
import baritone.bot.IBaritoneUser;
-import baritone.bot.entity.EntityBot;
+import baritone.bot.spec.BotWorld;
+import baritone.bot.spec.EntityBot;
+import baritone.utils.Helper;
import com.mojang.authlib.GameProfile;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
-import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.entity.player.PlayerCapabilities;
+import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.PacketBuffer;
@@ -40,12 +43,16 @@ import net.minecraft.network.play.server.*;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.scoreboard.*;
+import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.StringUtils;
+import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
+import net.minecraft.world.WorldProviderSurface;
+import net.minecraft.world.chunk.Chunk;
import javax.annotation.Nonnull;
@@ -88,7 +95,7 @@ public class BotNetHandlerPlayClient extends NetHandlerPlayClient {
/**
* The current world.
*/
- private WorldClient world;
+ private BotWorld world;
public BotNetHandlerPlayClient(NetworkManager networkManager, IBaritoneUser user, Minecraft client, GameProfile profile) {
// noinspection ConstantConditions
@@ -206,7 +213,7 @@ public class BotNetHandlerPlayClient extends NetHandlerPlayClient {
public void handleBlockChange(@Nonnull SPacketBlockChange packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
- this.world.invalidateRegionAndSetBlock(packetIn.getBlockPosition(), packetIn.getBlockState());
+ this.world.setBlockState(packetIn.getBlockPosition(), packetIn.getBlockState());
}
@Override
@@ -222,7 +229,7 @@ public class BotNetHandlerPlayClient extends NetHandlerPlayClient {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
for (SPacketMultiBlockChange.BlockUpdateData data : packetIn.getChangedBlocks()) {
- this.world.invalidateRegionAndSetBlock(data.getPos(), data.getBlockState());
+ this.world.setBlockState(data.getPos(), data.getBlockState());
}
}
@@ -305,11 +312,28 @@ public class BotNetHandlerPlayClient extends NetHandlerPlayClient {
@Override
public void handleChunkData(@Nonnull SPacketChunkData packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
+
+ if (packetIn.isFullChunk()) {
+ this.world.doPreChunk(packetIn.getChunkX(), packetIn.getChunkZ(), true);
+ }
+
+ Chunk chunk = this.world.getChunk(packetIn.getChunkX(), packetIn.getChunkZ());
+ chunk.read(packetIn.getReadBuffer(), packetIn.getExtractedSize(), packetIn.isFullChunk());
+
+ for (NBTTagCompound tag : packetIn.getTileEntityTags()) {
+ BlockPos pos = new BlockPos(tag.getInteger("x"), tag.getInteger("y"), tag.getInteger("z"));
+ TileEntity tileEntity = this.world.getTileEntity(pos);
+
+ if (tileEntity != null) {
+ tileEntity.readFromNBT(tag);
+ }
+ }
}
@Override
public void processChunkUnload(@Nonnull SPacketUnloadChunk packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
+ // TODO Unload chunks
}
@Override
@@ -321,23 +345,21 @@ public class BotNetHandlerPlayClient extends NetHandlerPlayClient {
public void handleJoinGame(@Nonnull SPacketJoinGame packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
- // TODO: Set world and player (See Below)
- /*
- - Create player controller
- - Set game difficulty
- - Create world
- - Load world
- - Create player
- - Set entity ID
- - Set player dimension
- - Set player
- - Spawn player into world
- - Set player game mode
- - Define max players? (Might be useful when determining if Bots are in the same world)
- */
+ this.world = this.user.getManager().getWorldProvider().getWorld(packetIn.getDimension());
+ this.player = new EntityBot(this.user, (Minecraft) this.client, this.world, this);
+ this.player.preparePlayerToSpawn();
+ this.world.spawnEntity(this.player);
+ this.player.setEntityId(packetIn.getPlayerId());
+ this.player.dimension = packetIn.getDimension();
+ this.player.setGameType(packetIn.getGameType());
+ packetIn.getGameType().configurePlayerCapabilities(this.player.capabilities);
this.networkManager.sendPacket(new CPacketClientSettings("en_us", 8, EntityPlayer.EnumChatVisibility.FULL, true, 0, EnumHandSide.RIGHT));
this.networkManager.sendPacket(new CPacketCustomPayload("MC|Brand", new PacketBuffer(Unpooled.buffer()).writeString("vanilla")));
+
+ this.world.registerBot(packetIn.getPlayerId(), this.player);
+
+ Helper.HELPER.logDirect("Initialized Player and World");
}
@Override
@@ -348,6 +370,47 @@ public class BotNetHandlerPlayClient extends NetHandlerPlayClient {
@Override
public void handlePlayerPosLook(@Nonnull SPacketPlayerPosLook packetIn) {
PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.client);
+
+ EntityPlayer player = this.player;
+ double d0 = packetIn.getX();
+ double d1 = packetIn.getY();
+ double d2 = packetIn.getZ();
+ float f = packetIn.getYaw();
+ float f1 = packetIn.getPitch();
+
+ if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.X)) {
+ d0 += player.posX;
+ } else {
+ player.motionX = 0.0D;
+ }
+
+ if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.Y)) {
+ d1 += player.posY;
+ } else {
+ player.motionY = 0.0D;
+ }
+
+ if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.Z)) {
+ d2 += player.posZ;
+ } else {
+ player.motionZ = 0.0D;
+ }
+
+ if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.X_ROT)) {
+ f1 += player.rotationPitch;
+ }
+
+ if (packetIn.getFlags().contains(SPacketPlayerPosLook.EnumFlags.Y_ROT)) {
+ f += player.rotationYaw;
+ }
+
+ player.setPositionAndRotation(d0, d1, d2, f, f1);
+ this.networkManager.sendPacket(new CPacketConfirmTeleport(packetIn.getTeleportId()));
+ this.networkManager.sendPacket(new CPacketPlayer.PositionRotation(player.posX, player.getEntityBoundingBox().minY, player.posZ, player.rotationYaw, player.rotationPitch, false));
+
+ this.player.prevPosX = this.player.posX;
+ this.player.prevPosY = this.player.posY;
+ this.player.prevPosZ = this.player.posZ;
}
@Override
diff --git a/src/main/java/baritone/bot/entity/BotMovementInput.java b/src/main/java/baritone/bot/spec/BotMovementInput.java
similarity index 96%
rename from src/main/java/baritone/bot/entity/BotMovementInput.java
rename to src/main/java/baritone/bot/spec/BotMovementInput.java
index b6177fde4..ccab9ad26 100644
--- a/src/main/java/baritone/bot/entity/BotMovementInput.java
+++ b/src/main/java/baritone/bot/spec/BotMovementInput.java
@@ -15,7 +15,7 @@
* along with Baritone. If not, see .
*/
-package baritone.bot.entity;
+package baritone.bot.spec;
import baritone.bot.IBaritoneUser;
import net.minecraft.util.MovementInput;
@@ -56,7 +56,7 @@ public class BotMovementInput extends MovementInput {
this.moveStrafe--;
}
- this.jump = jump;
+ this.jump = true;
if (this.sneak = sneak) {
this.moveStrafe *= 0.3D;
diff --git a/src/main/java/baritone/bot/spec/BotWorld.java b/src/main/java/baritone/bot/spec/BotWorld.java
new file mode 100644
index 000000000..7b2ff6c41
--- /dev/null
+++ b/src/main/java/baritone/bot/spec/BotWorld.java
@@ -0,0 +1,84 @@
+/*
+ * 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.spec;
+
+import net.minecraft.client.multiplayer.ChunkProviderClient;
+import net.minecraft.entity.Entity;
+import net.minecraft.profiler.Profiler;
+import net.minecraft.world.DimensionType;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldSettings;
+import net.minecraft.world.chunk.IChunkProvider;
+import net.minecraft.world.storage.SaveHandlerMP;
+import net.minecraft.world.storage.WorldInfo;
+
+import javax.annotation.Nonnull;
+
+/**
+ * @author Brady
+ * @since 11/7/2018
+ */
+public class BotWorld extends World {
+
+ private static Profiler BOT_WORLD_PROFILER = new Profiler();
+ private static int worldNum = 0;
+
+ private ChunkProviderClient chunkProviderClient;
+
+ public BotWorld(WorldSettings settings, int dimension) {
+ super(
+ new SaveHandlerMP(),
+ new WorldInfo(settings, "BotWorld" + ++worldNum),
+ DimensionType.getById(dimension).createDimension(),
+ BOT_WORLD_PROFILER,
+ true
+ );
+ this.provider.setWorld(this);
+ this.chunkProvider = this.createChunkProvider();
+ }
+
+ @Override
+ @Nonnull
+ protected IChunkProvider createChunkProvider() {
+ return (this.chunkProviderClient = new ChunkProviderClient(this));
+ }
+
+ @Override
+ protected boolean isChunkLoaded(int x, int z, boolean allowEmpty) {
+ return allowEmpty || !this.chunkProviderClient.provideChunk(x, z).isEmpty();
+ }
+
+ public void registerBot(int entityID, EntityBot entity) {
+ this.entitiesById.addKey(entityID, entity);
+ }
+
+ public void removeEntityFromWorld(int entityID) {
+ Entity entity = this.entitiesById.removeObject(entityID);
+ if (entity != null) {
+ this.removeEntity(entity);
+ }
+ }
+
+ public void doPreChunk(int chunkX, int chunkZ, boolean loadChunk) {
+ if (loadChunk) {
+ this.chunkProviderClient.loadChunk(chunkX, chunkZ);
+ } else {
+ this.chunkProviderClient.unloadChunk(chunkX, chunkZ);
+ }
+ }
+}
diff --git a/src/main/java/baritone/bot/entity/EntityBot.java b/src/main/java/baritone/bot/spec/EntityBot.java
similarity index 82%
rename from src/main/java/baritone/bot/entity/EntityBot.java
rename to src/main/java/baritone/bot/spec/EntityBot.java
index 1e233045a..48e13dc8c 100644
--- a/src/main/java/baritone/bot/entity/EntityBot.java
+++ b/src/main/java/baritone/bot/spec/EntityBot.java
@@ -15,17 +15,20 @@
* along with Baritone. If not, see .
*/
-package baritone.bot.entity;
+package baritone.bot.spec;
import baritone.bot.IBaritoneUser;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.network.NetHandlerPlayClient;
+import net.minecraft.client.network.NetworkPlayerInfo;
+import net.minecraft.client.util.RecipeBookClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.IMerchant;
import net.minecraft.entity.passive.AbstractHorse;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
+import net.minecraft.network.play.client.CPacketPlayer;
import net.minecraft.stats.RecipeBook;
import net.minecraft.stats.StatisticsManager;
import net.minecraft.tileentity.CommandBlockBaseLogic;
@@ -33,10 +36,13 @@ import net.minecraft.tileentity.TileEntityCommandBlock;
import net.minecraft.tileentity.TileEntitySign;
import net.minecraft.tileentity.TileEntityStructure;
import net.minecraft.util.EnumHand;
+import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.IInteractionObject;
import net.minecraft.world.World;
+import javax.annotation.Nullable;
+
// Some Notes:
// startRiding references the sound manager
// onUpdateWalkingPlayer references the gameSettings autoJump flag
@@ -58,9 +64,10 @@ public class EntityBot extends EntityPlayerSP {
private final IBaritoneUser user;
- public EntityBot(IBaritoneUser user, Minecraft mc, World world, NetHandlerPlayClient netHandlerPlayClient, StatisticsManager statisticsManager, RecipeBook recipeBook) {
- super(mc, world, netHandlerPlayClient, statisticsManager, recipeBook);
+ public EntityBot(IBaritoneUser user, Minecraft mc, World world, NetHandlerPlayClient netHandlerPlayClient) {
+ super(mc, world, netHandlerPlayClient, new StatisticsManager(), new RecipeBookClient());
this.user = user;
+ this.movementInput = new BotMovementInput(this.user);
}
@Override
@@ -138,7 +145,25 @@ public class EntityBot extends EntityPlayerSP {
@Override
protected boolean isCurrentViewEntity() {
- // Don't you even try @leijurv
- return false;
+ return true;
+ }
+
+ @Override
+ public boolean isSpectator() {
+ // TODO
+ return super.isSpectator();
+ }
+
+ @Override
+ public boolean isCreative() {
+ // TODO
+ return super.isCreative();
+ }
+
+ @Nullable
+ @Override
+ protected NetworkPlayerInfo getPlayerInfo() {
+ // TODO
+ return super.getPlayerInfo();
}
}