2021-06-27 00:26:45 -05:00
|
|
|
package net.nuggetmc.ai.bot;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
|
|
|
|
import com.mojang.authlib.GameProfile;
|
|
|
|
|
import net.minecraft.server.v1_16_R3.*;
|
|
|
|
|
import net.nuggetmc.ai.PlayerAI;
|
2021-06-28 13:18:49 -05:00
|
|
|
import net.nuggetmc.ai.utils.MathUtils;
|
2021-06-26 19:43:58 -05:00
|
|
|
import net.nuggetmc.ai.utils.SteveUUID;
|
|
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
|
import org.bukkit.Location;
|
|
|
|
|
import org.bukkit.World;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
|
import org.bukkit.util.Vector;
|
|
|
|
|
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
2021-06-27 00:26:45 -05:00
|
|
|
public class Bot extends EntityPlayer {
|
2021-06-26 19:43:58 -05:00
|
|
|
|
|
|
|
|
public Vector velocity;
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
private byte aliveTicks;
|
2021-06-26 19:43:58 -05:00
|
|
|
private byte kbTicks;
|
2021-06-28 15:17:32 -05:00
|
|
|
private byte jumpTicks;
|
|
|
|
|
private byte groundTicks;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-26 20:00:57 -05:00
|
|
|
private final double regenAmount = 0.05;
|
2021-06-28 15:17:32 -05:00
|
|
|
private final double frictionMin = 0.01;
|
|
|
|
|
private final double kbUp = 0.3;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
private Vector offset;
|
|
|
|
|
|
2021-06-27 00:26:45 -05:00
|
|
|
public Bot(MinecraftServer minecraftServer, WorldServer worldServer, GameProfile profile, PlayerInteractManager manager) {
|
2021-06-26 19:43:58 -05:00
|
|
|
super(minecraftServer, worldServer, profile, manager);
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
this.velocity = new Vector(0, 0, 0);
|
|
|
|
|
this.offset = MathUtils.circleOffset(3);
|
2021-06-29 17:05:11 -05:00
|
|
|
|
|
|
|
|
datawatcher.set(new DataWatcherObject<>(16, DataWatcherRegistry.a), (byte) 0xFF);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-28 13:18:49 -05:00
|
|
|
public static Bot createBot(Location loc, String name, String skin) {
|
2021-06-26 19:43:58 -05:00
|
|
|
MinecraftServer nmsServer = ((CraftServer) Bukkit.getServer()).getServer();
|
|
|
|
|
WorldServer nmsWorld = ((CraftWorld) loc.getWorld()).getHandle();
|
|
|
|
|
|
|
|
|
|
UUID uuid = SteveUUID.generate();
|
|
|
|
|
|
2021-06-29 17:05:11 -05:00
|
|
|
CustomGameProfile profile = new CustomGameProfile(uuid, name, skin);
|
2021-06-26 19:43:58 -05:00
|
|
|
PlayerInteractManager interactManager = new PlayerInteractManager(nmsWorld);
|
|
|
|
|
|
2021-06-27 00:26:45 -05:00
|
|
|
Bot bot = new Bot(nmsServer, nmsWorld, profile, interactManager);
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-27 00:26:45 -05:00
|
|
|
bot.playerConnection = new PlayerConnection(nmsServer, new NetworkManager(EnumProtocolDirection.CLIENTBOUND), bot);
|
|
|
|
|
bot.setLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
|
|
|
|
|
bot.getBukkitEntity().setNoDamageTicks(0);
|
|
|
|
|
nmsWorld.addEntity(bot);
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-29 17:05:11 -05:00
|
|
|
bot.renderAll();
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-27 00:26:45 -05:00
|
|
|
PlayerAI.getInstance().getManager().add(bot);
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-27 00:26:45 -05:00
|
|
|
return bot;
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-29 17:05:11 -05:00
|
|
|
private void renderAll() {
|
2021-06-26 19:43:58 -05:00
|
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
|
|
|
PlayerConnection connection = ((CraftPlayer) player).getHandle().playerConnection;
|
2021-06-29 16:43:19 -05:00
|
|
|
render(connection, false);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void render(PlayerConnection connection, boolean login) {
|
|
|
|
|
connection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, this));
|
|
|
|
|
connection.sendPacket(new PacketPlayOutNamedEntitySpawn(this));
|
|
|
|
|
connection.sendPacket(new PacketPlayOutEntityMetadata(this.getId(), this.getDataWatcher(), true));
|
|
|
|
|
|
|
|
|
|
PacketPlayOutEntityHeadRotation rotationPacket = new PacketPlayOutEntityHeadRotation(this, (byte) ((this.yaw * 256f) / 360f));
|
|
|
|
|
|
|
|
|
|
if (login) {
|
|
|
|
|
Bukkit.getScheduler().runTaskLater(PlayerAI.getInstance(), () -> connection.sendPacket(rotationPacket), 10);
|
|
|
|
|
} else {
|
|
|
|
|
connection.sendPacket(rotationPacket);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
public Vector getOffset() {
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 15:17:32 -05:00
|
|
|
public Vector getVelocity() {
|
|
|
|
|
return velocity.clone();
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
public void setVelocity(Vector vector) {
|
|
|
|
|
this.velocity = vector;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void addVelocity(Vector vector) {
|
2021-06-28 15:17:32 -05:00
|
|
|
try {
|
|
|
|
|
velocity.checkFinite();
|
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
|
velocity = vector;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
this.velocity.add(vector);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
public boolean tickDelay(int i) {
|
|
|
|
|
return aliveTicks % i == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
@Override
|
|
|
|
|
public void tick() {
|
|
|
|
|
super.tick();
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
aliveTicks++;
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
if (noDamageTicks > 0) --noDamageTicks;
|
|
|
|
|
if (kbTicks > 0) --kbTicks;
|
2021-06-28 15:17:32 -05:00
|
|
|
if (jumpTicks > 0) --jumpTicks;
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
if (isOnGround()) {
|
2021-06-28 15:17:32 -05:00
|
|
|
groundTicks++;
|
|
|
|
|
} else {
|
|
|
|
|
groundTicks = 0;
|
|
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-29 17:05:11 -05:00
|
|
|
Player botPlayer = getBukkitEntity();
|
2021-06-28 13:18:49 -05:00
|
|
|
if (botPlayer.isDead()) return;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-28 13:18:49 -05:00
|
|
|
double health = botPlayer.getHealth();
|
|
|
|
|
double maxHealth = botPlayer.getHealthScale();
|
2021-06-26 19:43:58 -05:00
|
|
|
double amount;
|
|
|
|
|
|
2021-06-26 20:00:57 -05:00
|
|
|
if (health < maxHealth - regenAmount) {
|
|
|
|
|
amount = health + regenAmount;
|
2021-06-26 19:43:58 -05:00
|
|
|
} else {
|
|
|
|
|
amount = maxHealth;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 13:18:49 -05:00
|
|
|
botPlayer.setHealth(amount);
|
2021-06-26 19:43:58 -05:00
|
|
|
|
|
|
|
|
updateLocation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void updateLocation() {
|
2021-06-28 03:14:07 -05:00
|
|
|
// Eventually there will be a whole algorithm here to slow a player down to a certain velocity depending on the liquid a player is in
|
|
|
|
|
|
2021-06-27 21:45:11 -05:00
|
|
|
double y;
|
|
|
|
|
|
2021-06-30 02:18:31 -05:00
|
|
|
if (groundTicks != 0) {
|
2021-06-26 19:43:58 -05:00
|
|
|
velocity.setY(0);
|
|
|
|
|
addFriction();
|
2021-06-27 21:45:11 -05:00
|
|
|
y = 0;
|
|
|
|
|
} else {
|
|
|
|
|
y = velocity.getY();
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-28 15:17:32 -05:00
|
|
|
velocity.setY(velocity.getY() - 0.1);
|
|
|
|
|
|
2021-06-27 21:45:11 -05:00
|
|
|
this.move(EnumMoveType.SELF, new Vec3D(velocity.getX(), y, velocity.getZ()));
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-28 15:17:32 -05:00
|
|
|
public void jump(Vector vel) {
|
|
|
|
|
if (jumpTicks == 0 && groundTicks > 1) {
|
|
|
|
|
jumpTicks = 4;
|
|
|
|
|
velocity = vel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
public void attack(org.bukkit.entity.Entity entity) {
|
|
|
|
|
faceLocation(entity.getLocation());
|
|
|
|
|
punch();
|
|
|
|
|
attack(((CraftEntity) entity).getHandle());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void punch() {
|
|
|
|
|
PacketPlayOutAnimation packet = new PacketPlayOutAnimation(this, 0);
|
|
|
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
|
|
|
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isOnGround() {
|
2021-06-26 19:43:58 -05:00
|
|
|
double vy = velocity.getY();
|
|
|
|
|
|
|
|
|
|
if (vy > 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
World world = getBukkitEntity().getWorld();
|
|
|
|
|
AxisAlignedBB box = getBoundingBox();
|
|
|
|
|
|
|
|
|
|
double[] xVals = new double[] {
|
2021-06-29 16:29:30 -05:00
|
|
|
box.minX,
|
|
|
|
|
box.maxX
|
2021-06-26 19:43:58 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
double[] zVals = new double[] {
|
2021-06-29 16:29:30 -05:00
|
|
|
box.minZ,
|
|
|
|
|
box.maxZ
|
2021-06-26 19:43:58 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (double x : xVals) {
|
|
|
|
|
for (double z : zVals) {
|
2021-06-29 16:29:30 -05:00
|
|
|
if (world.getBlockAt(new Location(world, x, locY() - 0.01, z)).getType().isSolid()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void addFriction() {
|
2021-06-28 15:17:32 -05:00
|
|
|
double x = velocity.getX();
|
|
|
|
|
double z = velocity.getZ();
|
|
|
|
|
|
|
|
|
|
velocity.setX(x < frictionMin ? 0 : x * 0.5);
|
|
|
|
|
velocity.setZ(z < frictionMin ? 0 : z * 0.5);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void despawn() {
|
2021-06-28 15:17:32 -05:00
|
|
|
getBukkitEntity().remove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void remove() {
|
2021-06-28 13:18:49 -05:00
|
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
|
|
|
PlayerConnection connection = ((CraftPlayer) player).getHandle().playerConnection;
|
|
|
|
|
connection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, this));
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
getBukkitEntity().remove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void collide(Entity entity) {
|
|
|
|
|
if (!this.isSameVehicle(entity) && !entity.noclip && !this.noclip) {
|
|
|
|
|
double d0 = entity.locX() - this.locX();
|
|
|
|
|
double d1 = entity.locZ() - this.locZ();
|
|
|
|
|
double d2 = MathHelper.a(d0, d1);
|
|
|
|
|
if (d2 >= 0.009999999776482582D) {
|
|
|
|
|
d2 = MathHelper.sqrt(d2);
|
|
|
|
|
d0 /= d2;
|
|
|
|
|
d1 /= d2;
|
|
|
|
|
double d3 = 1.0D / d2;
|
|
|
|
|
if (d3 > 1.0D) {
|
|
|
|
|
d3 = 1.0D;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d0 *= d3;
|
|
|
|
|
d1 *= d3;
|
|
|
|
|
d0 *= 0.05000000074505806D;
|
|
|
|
|
d1 *= 0.05000000074505806D;
|
|
|
|
|
d0 *= 1.0F - this.I;
|
|
|
|
|
d1 *= 1.0F - this.I;
|
|
|
|
|
|
|
|
|
|
if (!this.isVehicle()) {
|
|
|
|
|
velocity.add(new Vector(-d0 * 3, 0.0D, -d1 * 3));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!entity.isVehicle()) {
|
|
|
|
|
entity.i(d0, 0.0D, d1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean damageEntity(DamageSource damagesource, float f) {
|
|
|
|
|
boolean damaged = super.damageEntity(damagesource, f);
|
|
|
|
|
|
|
|
|
|
net.minecraft.server.v1_16_R3.Entity attacker = damagesource.getEntity();
|
|
|
|
|
|
|
|
|
|
if (damaged && kbTicks == 0 && attacker != null) {
|
|
|
|
|
Player player = getBukkitEntity();
|
|
|
|
|
CraftEntity entity = attacker.getBukkitEntity();
|
|
|
|
|
Location loc1 = player.getLocation();
|
|
|
|
|
Location loc2 = entity.getLocation();
|
|
|
|
|
|
2021-06-28 13:18:49 -05:00
|
|
|
kb(loc1, loc2);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return damaged;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 13:18:49 -05:00
|
|
|
private void kb(Location loc1, Location loc2) {
|
2021-06-30 02:18:31 -05:00
|
|
|
Vector diff = loc1.toVector().subtract(loc2.toVector()).normalize().setY(kbUp);
|
|
|
|
|
Vector vel = velocity.clone().add(diff).multiply(0.5);
|
2021-06-28 15:17:32 -05:00
|
|
|
|
|
|
|
|
if (vel.length() > 1) vel.normalize();
|
2021-06-30 02:18:31 -05:00
|
|
|
if (groundTicks != 0) vel.multiply(0.8).setY(0.4);
|
|
|
|
|
else if (vel.getY() > kbUp) vel.setY(kbUp);
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-06-28 15:17:32 -05:00
|
|
|
velocity = vel;
|
2021-06-26 19:43:58 -05:00
|
|
|
kbTicks = 10;
|
|
|
|
|
}
|
2021-06-28 03:14:07 -05:00
|
|
|
|
|
|
|
|
public Location getLocation() {
|
|
|
|
|
return getBukkitEntity().getLocation();
|
|
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
|
|
|
|
|
public void faceLocation(Location loc) {
|
2021-06-28 13:18:49 -05:00
|
|
|
CraftPlayer botPlayer = getBukkitEntity();
|
|
|
|
|
Vector dir = loc.toVector().subtract(botPlayer.getLocation().toVector());
|
|
|
|
|
|
|
|
|
|
float[] vals = MathUtils.fetchYawPitch(dir);
|
|
|
|
|
|
|
|
|
|
setYawPitch(vals[0], vals[1]);
|
|
|
|
|
|
|
|
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
|
|
|
PlayerConnection connection = ((CraftPlayer) player).getHandle().playerConnection;
|
|
|
|
|
connection.sendPacket(new PacketPlayOutEntityHeadRotation(botPlayer.getHandle(), (byte) (vals[0] * 256 / 360f)));
|
|
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void playerTick() {
|
|
|
|
|
if (this.hurtTicks > 0) {
|
|
|
|
|
this.hurtTicks -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entityBaseTick();
|
|
|
|
|
tickPotionEffects();
|
|
|
|
|
|
|
|
|
|
this.aU = (int) this.aT;
|
|
|
|
|
this.aL = this.aK;
|
|
|
|
|
this.lastYaw = this.yaw;
|
|
|
|
|
this.lastPitch = this.pitch;
|
|
|
|
|
}
|
|
|
|
|
}
|