From 484dac66b7d9d05e1ebb3a4cbe042a053cffdbc4 Mon Sep 17 00:00:00 2001 From: Brady Date: Fri, 9 Nov 2018 13:58:55 -0600 Subject: [PATCH] JUMP --- src/main/java/baritone/bot/BaritoneUser.java | 2 +- .../java/baritone/bot/BotWorldProvider.java | 62 +++++++++++ src/main/java/baritone/bot/IBaritoneUser.java | 2 +- src/main/java/baritone/bot/UserManager.java | 21 +++- .../bot/handler/BotNetHandlerPlayClient.java | 101 ++++++++++++++---- .../{entity => spec}/BotMovementInput.java | 4 +- src/main/java/baritone/bot/spec/BotWorld.java | 84 +++++++++++++++ .../bot/{entity => spec}/EntityBot.java | 35 +++++- 8 files changed, 280 insertions(+), 31 deletions(-) create mode 100644 src/main/java/baritone/bot/BotWorldProvider.java rename src/main/java/baritone/bot/{entity => spec}/BotMovementInput.java (96%) create mode 100644 src/main/java/baritone/bot/spec/BotWorld.java rename src/main/java/baritone/bot/{entity => spec}/EntityBot.java (82%) 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(); } }