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;
|
2021-07-10 23:51:14 -05:00
|
|
|
import com.mojang.datafixers.util.Pair;
|
2021-07-21 13:52:21 -05:00
|
|
|
import net.minecraft.server.v1_16_R3.Chunk;
|
2021-06-26 19:43:58 -05:00
|
|
|
import net.minecraft.server.v1_16_R3.*;
|
2021-07-21 13:52:21 -05:00
|
|
|
import net.nuggetmc.ai.TerminatorPlus;
|
2021-07-24 23:34:07 -05:00
|
|
|
import net.nuggetmc.ai.bot.agent.Agent;
|
2021-07-23 03:47:11 -05:00
|
|
|
import net.nuggetmc.ai.bot.agent.legacyagent.ai.NeuralNetwork;
|
2021-07-23 17:25:10 -05:00
|
|
|
import net.nuggetmc.ai.bot.event.BotDamageByPlayerEvent;
|
2021-07-19 17:35:28 -05:00
|
|
|
import net.nuggetmc.ai.bot.event.BotFallDamageEvent;
|
2021-07-24 23:34:07 -05:00
|
|
|
import net.nuggetmc.ai.bot.event.BotKilledByPlayerEvent;
|
2021-07-23 17:25:10 -05:00
|
|
|
import net.nuggetmc.ai.utils.*;
|
2021-07-10 23:51:14 -05:00
|
|
|
import org.bukkit.Material;
|
|
|
|
|
import org.bukkit.SoundCategory;
|
2021-06-26 19:43:58 -05:00
|
|
|
import org.bukkit.World;
|
2021-07-10 23:51:14 -05:00
|
|
|
import org.bukkit.*;
|
|
|
|
|
import org.bukkit.block.Block;
|
|
|
|
|
import org.bukkit.block.BlockFace;
|
2021-06-26 19:43:58 -05:00
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
2021-07-10 23:51:14 -05:00
|
|
|
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
2021-07-16 03:41:21 -05:00
|
|
|
import org.bukkit.entity.Damageable;
|
2021-06-26 19:43:58 -05:00
|
|
|
import org.bukkit.entity.Player;
|
2021-07-24 23:34:07 -05:00
|
|
|
import org.bukkit.inventory.ItemStack;
|
2021-07-23 17:25:10 -05:00
|
|
|
import org.bukkit.scheduler.BukkitScheduler;
|
2021-06-26 19:43:58 -05:00
|
|
|
import org.bukkit.util.Vector;
|
|
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
import java.util.ArrayList;
|
2021-07-16 03:41:21 -05:00
|
|
|
import java.util.Collections;
|
2021-07-09 15:49:10 -05:00
|
|
|
import java.util.Objects;
|
2021-06-26 19:43:58 -05:00
|
|
|
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
|
|
|
|
2021-07-23 17:25:10 -05:00
|
|
|
private final TerminatorPlus plugin;
|
|
|
|
|
private final BukkitScheduler scheduler;
|
2021-07-24 23:34:07 -05:00
|
|
|
private final Agent agent;
|
2021-07-23 17:25:10 -05:00
|
|
|
|
2021-07-23 03:47:11 -05:00
|
|
|
private NeuralNetwork network;
|
|
|
|
|
|
|
|
|
|
public NeuralNetwork getNeuralNetwork() {
|
|
|
|
|
return network;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setNeuralNetwork(NeuralNetwork network) {
|
|
|
|
|
this.network = network;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean hasNeuralNetwork() {
|
|
|
|
|
return network != null;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
public ItemStack defaultItem;
|
2021-07-23 17:25:10 -05:00
|
|
|
|
|
|
|
|
private boolean shield;
|
|
|
|
|
private boolean blocking;
|
|
|
|
|
private boolean blockUse;
|
2021-07-21 13:52:21 -05:00
|
|
|
|
2021-07-23 03:47:11 -05:00
|
|
|
private Vector velocity;
|
2021-07-16 03:41:21 -05:00
|
|
|
private Vector oldVelocity;
|
|
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
private boolean removeOnDeath;
|
|
|
|
|
|
|
|
|
|
private int aliveTicks;
|
|
|
|
|
private int kills;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
private byte fireTicks;
|
2021-06-28 15:17:32 -05:00
|
|
|
private byte groundTicks;
|
2021-07-16 03:41:21 -05:00
|
|
|
private byte jumpTicks;
|
|
|
|
|
private byte noFallTicks;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-07-09 15:49:10 -05:00
|
|
|
private final Vector offset;
|
2021-06-29 16:29:30 -05:00
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
private Bot(MinecraftServer minecraftServer, WorldServer worldServer, GameProfile profile, PlayerInteractManager manager) {
|
2021-06-26 19:43:58 -05:00
|
|
|
super(minecraftServer, worldServer, profile, manager);
|
|
|
|
|
|
2021-07-23 17:25:10 -05:00
|
|
|
this.plugin = TerminatorPlus.getInstance();
|
|
|
|
|
this.scheduler = Bukkit.getScheduler();
|
2021-07-24 23:34:07 -05:00
|
|
|
this.agent = plugin.getManager().getAgent();
|
|
|
|
|
this.defaultItem = new ItemStack(Material.AIR);
|
2021-06-29 16:29:30 -05:00
|
|
|
this.velocity = new Vector(0, 0, 0);
|
2021-07-16 03:41:21 -05:00
|
|
|
this.oldVelocity = velocity.clone();
|
|
|
|
|
this.noFallTicks = 60;
|
|
|
|
|
this.fireTicks = 0;
|
2021-07-23 03:47:11 -05:00
|
|
|
this.removeOnDeath = true;
|
2021-06-29 16:29:30 -05:00
|
|
|
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-07-21 13:52:21 -05:00
|
|
|
public static Bot createBot(Location loc, String name) {
|
2021-07-23 03:47:11 -05:00
|
|
|
return createBot(loc, name, MojangAPI.getSkin(name));
|
2021-07-21 13:52:21 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-23 03:47:11 -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();
|
2021-07-09 15:49:10 -05:00
|
|
|
WorldServer nmsWorld = ((CraftWorld) Objects.requireNonNull(loc.getWorld())).getHandle();
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-07-12 18:24:10 -05:00
|
|
|
UUID uuid = BotUtils.randomSteveUUID();
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-07-23 03:47:11 -05:00
|
|
|
CustomGameProfile profile = new CustomGameProfile(uuid, StringUtilities.trim16(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-07-21 13:52:21 -05:00
|
|
|
TerminatorPlus.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-07-10 23:51:14 -05:00
|
|
|
private void renderAll() {
|
|
|
|
|
Packet<?>[] packets = getRenderPackets();
|
|
|
|
|
Bukkit.getOnlinePlayers().forEach(p -> render(((CraftPlayer) p).getHandle().playerConnection, packets, false));
|
|
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
private void render(PlayerConnection connection, Packet<?>[] packets, boolean login) {
|
2021-07-10 23:51:14 -05:00
|
|
|
connection.sendPacket(packets[0]);
|
|
|
|
|
connection.sendPacket(packets[1]);
|
|
|
|
|
connection.sendPacket(packets[2]);
|
2021-06-26 19:43:58 -05:00
|
|
|
|
|
|
|
|
if (login) {
|
2021-07-23 17:25:10 -05:00
|
|
|
scheduler.runTaskLater(plugin, () -> connection.sendPacket(packets[3]), 10);
|
2021-06-26 19:43:58 -05:00
|
|
|
} else {
|
2021-07-10 23:51:14 -05:00
|
|
|
connection.sendPacket(packets[3]);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
public void render(PlayerConnection connection, boolean login) {
|
|
|
|
|
render(connection, getRenderPackets(), login);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Packet<?>[] getRenderPackets() {
|
|
|
|
|
return new Packet[] {
|
|
|
|
|
new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, this),
|
|
|
|
|
new PacketPlayOutNamedEntitySpawn(this),
|
|
|
|
|
new PacketPlayOutEntityMetadata(this.getId(), this.getDataWatcher(), true),
|
|
|
|
|
new PacketPlayOutEntityHeadRotation(this, (byte) ((this.yaw * 256f) / 360f))
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
public void setDefaultItem(ItemStack item) {
|
|
|
|
|
this.defaultItem = item;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 17:35:28 -05:00
|
|
|
public void addVelocity(Vector vector) { // This can cause lag? (maybe i fixed it with the new static method)
|
|
|
|
|
if (MathUtils.isNotFinite(vector)) {
|
2021-06-28 15:17:32 -05:00
|
|
|
velocity = vector;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 17:35:28 -05:00
|
|
|
velocity.add(vector);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
public int getAliveTicks() {
|
|
|
|
|
return aliveTicks;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
public boolean tickDelay(int i) {
|
|
|
|
|
return aliveTicks % i == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
private void sendPacket(Packet<?> packet) {
|
|
|
|
|
Bukkit.getOnlinePlayers().forEach(p -> ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet));
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
@Override
|
|
|
|
|
public void tick() {
|
2021-07-21 13:52:21 -05:00
|
|
|
loadChunks();
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
super.tick();
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
if (!isAlive()) return;
|
|
|
|
|
|
2021-06-29 16:29:30 -05:00
|
|
|
aliveTicks++;
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
if (fireTicks > 0) --fireTicks;
|
2021-06-26 19:43:58 -05:00
|
|
|
if (noDamageTicks > 0) --noDamageTicks;
|
2021-06-28 15:17:32 -05:00
|
|
|
if (jumpTicks > 0) --jumpTicks;
|
2021-07-16 03:41:21 -05:00
|
|
|
if (noFallTicks > 0) --noFallTicks;
|
2021-06-28 15:17:32 -05:00
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
if (checkGround()) {
|
|
|
|
|
if (groundTicks < 5) groundTicks++;
|
2021-06-28 15:17:32 -05:00
|
|
|
} else {
|
|
|
|
|
groundTicks = 0;
|
|
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-07-04 03:15:30 -05:00
|
|
|
updateLocation();
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
float health = getHealth();
|
|
|
|
|
float maxHealth = getMaxHealth();
|
2021-07-21 13:52:21 -05:00
|
|
|
float regenAmount = 0.025f;
|
2021-07-16 03:41:21 -05:00
|
|
|
float amount;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
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-07-16 03:41:21 -05:00
|
|
|
setHealth(amount);
|
|
|
|
|
|
|
|
|
|
fireDamageCheck();
|
|
|
|
|
fallDamageCheck();
|
|
|
|
|
|
|
|
|
|
oldVelocity = velocity.clone();
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-21 13:52:21 -05:00
|
|
|
private void loadChunks() {
|
|
|
|
|
net.minecraft.server.v1_16_R3.World world = getWorld();
|
|
|
|
|
|
|
|
|
|
for (int i = chunkX - 1; i <= chunkX + 1; i++) {
|
|
|
|
|
for (int j = chunkZ - 1; j <= chunkZ + 1; j++) {
|
|
|
|
|
Chunk chunk = world.getChunkAt(i, j);
|
|
|
|
|
|
|
|
|
|
if (!chunk.loaded) {
|
|
|
|
|
chunk.setLoaded(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
private void fireDamageCheck() {
|
2021-07-19 17:35:28 -05:00
|
|
|
if (!isAlive()) {
|
|
|
|
|
return; // maybe also have packet reset thing
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
Material type = getLocation().getBlock().getType();
|
|
|
|
|
|
2021-07-19 17:35:28 -05:00
|
|
|
if (type == Material.WATER) {
|
|
|
|
|
setOnFirePackets(false); // maybe also play extinguish noise?
|
|
|
|
|
fireTicks = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
boolean lava = type == org.bukkit.Material.LAVA;
|
|
|
|
|
|
|
|
|
|
if (lava || type == org.bukkit.Material.FIRE || type == Material.SOUL_FIRE) {
|
|
|
|
|
ignite();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (noDamageTicks == 0) {
|
|
|
|
|
if (lava) {
|
|
|
|
|
damageEntity(DamageSource.LAVA, 4);
|
|
|
|
|
noDamageTicks = 12;
|
|
|
|
|
} else if (fireTicks > 1) {
|
|
|
|
|
damageEntity(DamageSource.FIRE, 1);
|
|
|
|
|
noDamageTicks = 20;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fireTicks == 1) {
|
|
|
|
|
setOnFirePackets(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ignite() {
|
|
|
|
|
if (fireTicks <= 1) setOnFirePackets(true);
|
|
|
|
|
fireTicks = 100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setOnFirePackets(boolean onFire) {
|
|
|
|
|
datawatcher.set(new DataWatcherObject<>(0, DataWatcherRegistry.a), onFire ? (byte) 1 : (byte) 0);
|
|
|
|
|
sendPacket(new PacketPlayOutEntityMetadata(getId(), datawatcher, false));
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 17:35:28 -05:00
|
|
|
public boolean isOnFire() {
|
|
|
|
|
return fireTicks != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fallDamageCheck() { // TODO create a better bot event system in the future, also have bot.getAgent()
|
|
|
|
|
if (groundTicks != 0 && noFallTicks == 0 && !(oldVelocity.getY() >= -0.8) && !BotUtils.NO_FALL.contains(getLocation().getBlock().getType())) {
|
|
|
|
|
BotFallDamageEvent event = new BotFallDamageEvent(this);
|
2021-07-16 03:41:21 -05:00
|
|
|
|
2021-07-23 17:25:10 -05:00
|
|
|
plugin.getManager().getAgent().onFallDamage(event);
|
2021-07-19 17:35:28 -05:00
|
|
|
|
|
|
|
|
if (!event.isCancelled()) {
|
|
|
|
|
damageEntity(DamageSource.FALL, (float) Math.pow(3.6, -oldVelocity.getY()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isFalling() {
|
|
|
|
|
return velocity.getY() < -0.8;
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-23 17:25:10 -05:00
|
|
|
public void block(int blockLength, int cooldown) {
|
|
|
|
|
if (!shield || blockUse) return;
|
|
|
|
|
startBlocking();
|
|
|
|
|
scheduler.runTaskLater(plugin, () -> stopBlocking(cooldown), blockLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void startBlocking() {
|
|
|
|
|
this.blocking = true;
|
|
|
|
|
this.blockUse = true;
|
|
|
|
|
c(EnumHand.OFF_HAND);
|
|
|
|
|
sendPacket(new PacketPlayOutEntityMetadata(getId(), datawatcher, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void stopBlocking(int cooldown) {
|
|
|
|
|
this.blocking = false;
|
|
|
|
|
clearActiveItem();
|
|
|
|
|
scheduler.runTaskLater(plugin, () -> this.blockUse = false, cooldown);
|
|
|
|
|
sendPacket(new PacketPlayOutEntityMetadata(getId(), datawatcher, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isBlocking() {
|
|
|
|
|
return blocking;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setShield(boolean enabled) {
|
|
|
|
|
this.shield = enabled;
|
|
|
|
|
|
|
|
|
|
setItemOffhand(new org.bukkit.inventory.ItemStack(enabled ? Material.SHIELD : Material.AIR));
|
2021-07-23 03:47:11 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-26 19:43:58 -05:00
|
|
|
private void updateLocation() {
|
2021-06-27 21:45:11 -05:00
|
|
|
double y;
|
|
|
|
|
|
2021-07-19 17:35:28 -05:00
|
|
|
MathUtils.clean(velocity); // TODO lag????
|
|
|
|
|
|
2021-07-12 18:20:17 -05:00
|
|
|
if (isInWater()) {
|
|
|
|
|
y = Math.min(velocity.getY() + 0.1, 0.1);
|
|
|
|
|
addFriction(0.8);
|
|
|
|
|
velocity.setY(y);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-12 18:20:17 -05:00
|
|
|
else {
|
|
|
|
|
if (groundTicks != 0) {
|
|
|
|
|
velocity.setY(0);
|
|
|
|
|
addFriction(0.5);
|
|
|
|
|
y = 0;
|
|
|
|
|
} else {
|
|
|
|
|
y = velocity.getY();
|
2021-07-19 17:35:28 -05:00
|
|
|
velocity.setY(Math.max(y - 0.1, -3.5));
|
2021-07-12 18:20:17 -05:00
|
|
|
}
|
|
|
|
|
}
|
2021-06-28 15:17:32 -05:00
|
|
|
|
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-07-12 18:20:17 -05:00
|
|
|
@Override
|
|
|
|
|
public boolean isInWater() {
|
|
|
|
|
Location loc = getLocation();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i <= 2; i++) {
|
|
|
|
|
Material type = loc.getBlock().getType();
|
|
|
|
|
|
|
|
|
|
if (type == Material.WATER || type == Material.LAVA) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loc.add(0, 0.9, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 15:17:32 -05:00
|
|
|
public void jump(Vector vel) {
|
|
|
|
|
if (jumpTicks == 0 && groundTicks > 1) {
|
|
|
|
|
jumpTicks = 4;
|
|
|
|
|
velocity = vel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-01 01:12:18 -05:00
|
|
|
public void jump() {
|
|
|
|
|
jump(new Vector(0, 0.5, 0));
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-23 03:47:11 -05:00
|
|
|
public void walk(Vector vel) {
|
|
|
|
|
double max = 0.4;
|
|
|
|
|
|
|
|
|
|
Vector sum = velocity.clone().add(vel);
|
|
|
|
|
if (sum.length() > max) sum.normalize().multiply(max);
|
|
|
|
|
|
|
|
|
|
velocity = sum;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 03:59:24 -05:00
|
|
|
public void attack(org.bukkit.entity.Entity entity) {
|
2021-06-29 16:29:30 -05:00
|
|
|
faceLocation(entity.getLocation());
|
|
|
|
|
punch();
|
2021-07-16 03:41:21 -05:00
|
|
|
|
|
|
|
|
if (entity instanceof Damageable) {
|
2021-07-24 23:34:07 -05:00
|
|
|
((Damageable) entity).damage(ItemUtils.getLegacyAttackDamage(defaultItem), getBukkitEntity());
|
2021-07-16 03:41:21 -05:00
|
|
|
}
|
2021-06-29 16:29:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void punch() {
|
2021-07-04 03:15:30 -05:00
|
|
|
swingHand(EnumHand.MAIN_HAND);
|
2021-06-29 16:29:30 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
public boolean checkGround() {
|
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-07-12 18:20:17 -05:00
|
|
|
box.minX,
|
|
|
|
|
box.maxX
|
2021-06-26 19:43:58 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
double[] zVals = new double[] {
|
2021-07-12 18:20:17 -05:00
|
|
|
box.minZ,
|
|
|
|
|
box.maxZ
|
2021-06-26 19:43:58 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (double x : xVals) {
|
|
|
|
|
for (double z : zVals) {
|
2021-07-12 18:20:17 -05:00
|
|
|
Location loc = new Location(world, x, locY() - 0.01, z);
|
|
|
|
|
Block block = world.getBlockAt(loc);
|
|
|
|
|
|
|
|
|
|
if (block.getType().isSolid() && BotUtils.solidAt(loc)) {
|
2021-06-29 16:29:30 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
@Override
|
|
|
|
|
public boolean isOnGround() {
|
|
|
|
|
return groundTicks != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 18:20:17 -05:00
|
|
|
public void addFriction(double factor) {
|
2021-07-09 15:49:10 -05:00
|
|
|
double frictionMin = 0.01;
|
|
|
|
|
|
2021-06-28 15:17:32 -05:00
|
|
|
double x = velocity.getX();
|
|
|
|
|
double z = velocity.getZ();
|
|
|
|
|
|
2021-07-12 18:20:17 -05:00
|
|
|
velocity.setX(Math.abs(x) < frictionMin ? 0 : x * factor);
|
|
|
|
|
velocity.setZ(Math.abs(z) < frictionMin ? 0 : z * factor);
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
public void removeVisually() {
|
|
|
|
|
this.removeTab();
|
|
|
|
|
this.setDead();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void removeTab() {
|
|
|
|
|
sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, this));
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
public void setRemoveOnDeath(boolean enabled) {
|
|
|
|
|
this.removeOnDeath = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
private void setDead() {
|
|
|
|
|
this.dead = true;
|
|
|
|
|
this.defaultContainer.b(this);
|
|
|
|
|
if (this.activeContainer != null) {
|
|
|
|
|
this.activeContainer.b(this);
|
2021-06-28 13:18:49 -05:00
|
|
|
}
|
2021-07-16 03:41:21 -05:00
|
|
|
}
|
2021-06-28 13:18:49 -05:00
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
private void dieCheck() {
|
|
|
|
|
if (removeOnDeath) {
|
2021-07-23 17:25:10 -05:00
|
|
|
scheduler.runTask(plugin, () -> plugin.getManager().remove(this));
|
|
|
|
|
scheduler.runTaskLater(plugin, this::setDead, 30);
|
2021-07-23 03:47:11 -05:00
|
|
|
|
|
|
|
|
this.removeTab();
|
2021-07-16 03:41:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void die() {
|
|
|
|
|
super.die();
|
|
|
|
|
this.dieCheck();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void die(DamageSource damageSource) {
|
|
|
|
|
super.die(damageSource);
|
|
|
|
|
this.dieCheck();
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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) {
|
|
|
|
|
net.minecraft.server.v1_16_R3.Entity attacker = damagesource.getEntity();
|
|
|
|
|
|
2021-07-23 17:25:10 -05:00
|
|
|
float damage;
|
|
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
boolean playerInstance = attacker instanceof EntityPlayer;
|
2021-07-23 17:25:10 -05:00
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
Player killer;
|
2021-06-26 19:43:58 -05:00
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
if (playerInstance) {
|
|
|
|
|
killer = ((EntityPlayer) attacker).getBukkitEntity();
|
|
|
|
|
|
|
|
|
|
BotDamageByPlayerEvent event = new BotDamageByPlayerEvent(this, killer, f);
|
|
|
|
|
|
|
|
|
|
agent.onPlayerDamage(event);
|
2021-07-23 17:25:10 -05:00
|
|
|
|
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
damage = event.getDamage();
|
|
|
|
|
} else {
|
2021-07-24 23:34:07 -05:00
|
|
|
killer = null;
|
2021-07-23 17:25:10 -05:00
|
|
|
damage = f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean damaged = super.damageEntity(damagesource, damage);
|
|
|
|
|
|
|
|
|
|
if (!damaged && blocking) {
|
|
|
|
|
getBukkitEntity().getWorld().playSound(getLocation(), Sound.ITEM_SHIELD_BLOCK, 1, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (damaged && attacker != null) {
|
2021-07-24 23:34:07 -05:00
|
|
|
if (playerInstance && !isAlive()) {
|
|
|
|
|
agent.onBotKilledByPlayer(new BotKilledByPlayerEvent(this, killer));
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-23 17:25:10 -05:00
|
|
|
kb(getLocation(), attacker.getBukkitEntity().getLocation());
|
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-07-10 23:51:14 -05:00
|
|
|
Vector vel = loc1.toVector().subtract(loc2.toVector()).setY(0).normalize().multiply(0.3);
|
2021-06-28 15:17:32 -05:00
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
if (isOnGround()) vel.multiply(0.8).setY(0.4);
|
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
|
|
|
}
|
2021-06-28 03:14:07 -05:00
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
public int getKills() {
|
|
|
|
|
return kills;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void incrementKills() {
|
|
|
|
|
kills++;
|
|
|
|
|
}
|
|
|
|
|
|
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-07-10 23:51:14 -05:00
|
|
|
look(loc.toVector().subtract(getLocation().toVector()), false);
|
|
|
|
|
}
|
2021-06-28 13:18:49 -05:00
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
public void look(BlockFace face) {
|
|
|
|
|
look(face.getDirection(), face == BlockFace.DOWN || face == BlockFace.UP);
|
|
|
|
|
}
|
2021-06-28 13:18:49 -05:00
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
private void look(Vector dir, boolean keepYaw) {
|
|
|
|
|
float yaw, pitch;
|
2021-06-28 13:18:49 -05:00
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
if (keepYaw) {
|
|
|
|
|
yaw = this.yaw;
|
|
|
|
|
pitch = MathUtils.fetchPitch(dir);
|
|
|
|
|
} else {
|
|
|
|
|
float[] vals = MathUtils.fetchYawPitch(dir);
|
|
|
|
|
yaw = vals[0];
|
|
|
|
|
pitch = vals[1];
|
2021-07-12 18:20:17 -05:00
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
sendPacket(new PacketPlayOutEntityHeadRotation(getBukkitEntity().getHandle(), (byte) (yaw * 256 / 360f)));
|
2021-07-10 23:51:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setYawPitch(yaw, pitch);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 17:35:28 -05:00
|
|
|
public void attemptBlockPlace(Location loc, Material type, boolean down) {
|
|
|
|
|
if (down) {
|
|
|
|
|
look(BlockFace.DOWN);
|
|
|
|
|
} else {
|
|
|
|
|
faceLocation(loc);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
setItem(new org.bukkit.inventory.ItemStack(Material.COBBLESTONE));
|
|
|
|
|
punch();
|
|
|
|
|
|
|
|
|
|
Block block = loc.getBlock();
|
|
|
|
|
World world = loc.getWorld();
|
|
|
|
|
|
|
|
|
|
if (!block.getType().isSolid()) {
|
|
|
|
|
block.setType(type);
|
|
|
|
|
if (world != null) world.playSound(loc, Sound.BLOCK_STONE_PLACE, SoundCategory.BLOCKS, 1, 1);
|
2021-06-28 13:18:49 -05:00
|
|
|
}
|
2021-06-26 19:43:58 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
public void setItem(org.bukkit.inventory.ItemStack item) {
|
2021-07-23 17:25:10 -05:00
|
|
|
setItem(item, EnumItemSlot.MAINHAND);
|
|
|
|
|
}
|
2021-07-10 23:51:14 -05:00
|
|
|
|
2021-07-23 17:25:10 -05:00
|
|
|
public void setItemOffhand(org.bukkit.inventory.ItemStack item) {
|
|
|
|
|
setItem(item, EnumItemSlot.OFFHAND);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-24 23:34:07 -05:00
|
|
|
private void setItem(org.bukkit.inventory.ItemStack item, EnumItemSlot slot) {
|
|
|
|
|
if (item == null) item = defaultItem;
|
2021-07-23 17:25:10 -05:00
|
|
|
|
|
|
|
|
if (slot == EnumItemSlot.MAINHAND) {
|
|
|
|
|
getBukkitEntity().getInventory().setItemInMainHand(item);
|
|
|
|
|
} else if (slot == EnumItemSlot.OFFHAND) {
|
|
|
|
|
getBukkitEntity().getInventory().setItemInOffHand(item);
|
|
|
|
|
}
|
2021-07-10 23:51:14 -05:00
|
|
|
|
2021-07-16 03:41:21 -05:00
|
|
|
sendPacket(new PacketPlayOutEntityEquipment(getId(), new ArrayList<>(Collections.singletonList(
|
2021-07-23 17:25:10 -05:00
|
|
|
new Pair<>(slot, CraftItemStack.asNMSCopy(item))
|
2021-07-16 03:41:21 -05:00
|
|
|
))));
|
2021-07-10 23:51:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void swim() {
|
2021-07-12 18:20:17 -05:00
|
|
|
getBukkitEntity().setSwimming(true);
|
2021-07-10 23:51:14 -05:00
|
|
|
registerPose(EntityPose.SWIMMING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void sneak() {
|
2021-07-12 18:20:17 -05:00
|
|
|
getBukkitEntity().setSneaking(true);
|
2021-07-10 23:51:14 -05:00
|
|
|
registerPose(EntityPose.CROUCHING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void stand() {
|
2021-07-12 18:20:17 -05:00
|
|
|
Player player = getBukkitEntity();
|
|
|
|
|
player.setSneaking(false);
|
|
|
|
|
player.setSwimming(false);
|
|
|
|
|
|
2021-07-10 23:51:14 -05:00
|
|
|
registerPose(EntityPose.STANDING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void registerPose(EntityPose pose) {
|
|
|
|
|
datawatcher.set(DataWatcherRegistry.s.a(6), pose);
|
2021-07-16 03:41:21 -05:00
|
|
|
sendPacket(new PacketPlayOutEntityMetadata(getId(), datawatcher, false));
|
2021-07-10 23:51:14 -05:00
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|