This commit is contained in:
Brady
2018-11-09 13:58:55 -06:00
parent 40282cd140
commit 484dac66b7
8 changed files with 280 additions and 31 deletions

View File

@@ -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;

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<BotWorld> 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());
}
}

View File

@@ -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;

View File

@@ -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<IBaritoneUser> 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<IBaritoneUser> 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;
}
}

View File

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

View File

@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
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;

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
}
}

View File

@@ -15,17 +15,20 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
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();
}
}