|
|
|
@@ -18,12 +18,9 @@
|
|
|
|
|
*/
|
|
|
|
|
package plugin.mrtransistor.AFK;
|
|
|
|
|
|
|
|
|
|
import com.google.common.collect.ImmutableSet;
|
|
|
|
|
import com.mojang.authlib.GameProfile;
|
|
|
|
|
import com.mojang.authlib.properties.Property;
|
|
|
|
|
import net.minecraft.commands.arguments.EntityAnchorArgument;
|
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
|
|
|
import net.minecraft.core.Vec3i;
|
|
|
|
|
import net.minecraft.server.MinecraftServer;
|
|
|
|
|
import net.minecraft.server.TickTask;
|
|
|
|
|
import net.minecraft.server.level.ServerLevel;
|
|
|
|
@@ -31,26 +28,21 @@ import net.minecraft.server.level.ServerPlayer;
|
|
|
|
|
import net.minecraft.world.InteractionHand;
|
|
|
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
|
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
|
|
|
import net.minecraft.world.entity.Mob;
|
|
|
|
|
import net.minecraft.world.entity.monster.Zombie;
|
|
|
|
|
import net.minecraft.world.entity.projectile.LargeFireball;
|
|
|
|
|
import net.minecraft.world.item.*;
|
|
|
|
|
import net.minecraft.world.level.GameType;
|
|
|
|
|
import net.minecraft.world.level.Level;
|
|
|
|
|
import net.minecraft.world.level.PathNavigationRegion;
|
|
|
|
|
import net.minecraft.world.level.pathfinder.Path;
|
|
|
|
|
import net.minecraft.world.level.pathfinder.PathFinder;
|
|
|
|
|
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
|
|
|
|
|
import net.minecraft.world.phys.Vec3;
|
|
|
|
|
import org.bukkit.*;
|
|
|
|
|
import org.bukkit.configuration.ConfigurationSection;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftLivingEntity;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R3.CraftServer;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R3.entity.*;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_19_R3.util.CraftVector;
|
|
|
|
|
import org.bukkit.entity.Enderman;
|
|
|
|
|
import org.bukkit.entity.Entity;
|
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
|
import org.bukkit.entity.Villager;
|
|
|
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
|
|
|
import org.bukkit.util.RayTraceResult;
|
|
|
|
|
import org.bukkit.util.Vector;
|
|
|
|
@@ -61,13 +53,13 @@ import java.util.UUID;
|
|
|
|
|
import java.util.function.Predicate;
|
|
|
|
|
|
|
|
|
|
public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
private static double ARROW_DIST_COEFF = 0.16;
|
|
|
|
|
private static double ARROW_HEIGHT_COEFF = 0.03;
|
|
|
|
|
private static double SNOWBALL_DIST_COEFF = 0.45;
|
|
|
|
|
private static double SNOWBALL_HEIGHT_COEFF = 0.1;
|
|
|
|
|
private static double TRIDENT_DIST_COEFF = 0.26;
|
|
|
|
|
private static double TRIDENT_HEIGHT_COEFF = 0.055;
|
|
|
|
|
private LivingEntity target;
|
|
|
|
|
private static final float ARROW_DIST_COEFF = 0.16F;
|
|
|
|
|
private static final float ARROW_HEIGHT_COEFF = 0.03F;
|
|
|
|
|
private static final float SNOWBALL_DIST_COEFF = 0.45F;
|
|
|
|
|
private static final float SNOWBALL_HEIGHT_COEFF = 0.1F;
|
|
|
|
|
private static final float TRIDENT_DIST_COEFF = 0.26F;
|
|
|
|
|
private static final float TRIDENT_HEIGHT_COEFF = 0.055F;
|
|
|
|
|
private net.minecraft.world.entity.Entity target;
|
|
|
|
|
|
|
|
|
|
//WIP
|
|
|
|
|
//private Mob pathfindingMob;
|
|
|
|
@@ -107,12 +99,12 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DummyPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) {
|
|
|
|
|
super(server, world, profile, null);
|
|
|
|
|
super(server, world, profile);
|
|
|
|
|
dummies.add(this);
|
|
|
|
|
names.add(getScoreboardName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static DummyPlayer spawnBot(String name, Location location, org.bukkit.entity.Player spawner, boolean updateStats) { // some of this crap is redundant but it works
|
|
|
|
|
public static void spawnBot(String name, Location location, Player spawner, boolean updateStats) { // some of this crap is redundant but it works
|
|
|
|
|
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
|
|
|
|
|
ServerLevel world = (location != null && location.getWorld() != null) ? ((CraftWorld) location.getWorld()).getHandle()
|
|
|
|
|
: server.getLevel(Level.OVERWORLD);
|
|
|
|
@@ -149,7 +141,6 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
dummy.setGameMode(GameType.SURVIVAL);
|
|
|
|
|
}
|
|
|
|
|
dummy.getEntityData().set(DATA_PLAYER_MODE_CUSTOMISATION, (byte) 0xf7);
|
|
|
|
|
return dummy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@@ -224,8 +215,8 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
double nearestDistance = 0;
|
|
|
|
|
|
|
|
|
|
for (Entity e : nearbyEntities) {
|
|
|
|
|
if (!(e instanceof CraftLivingEntity)
|
|
|
|
|
|| e instanceof Player || e instanceof Enderman || e.isDead()) continue;
|
|
|
|
|
if (!(e instanceof CraftLivingEntity || e instanceof CraftFireball)
|
|
|
|
|
|| e instanceof Player || e instanceof Enderman || e instanceof Villager || e.isDead()) continue;
|
|
|
|
|
if ((nearest == null || e.getLocation().distanceSquared(getBukkitEntity().getLocation()) < nearestDistance)
|
|
|
|
|
&& bukkitEntity.hasLineOfSight(e)) {
|
|
|
|
|
nearest = e;
|
|
|
|
@@ -233,7 +224,7 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nearest != null) {
|
|
|
|
|
target = (LivingEntity) ((CraftEntity) nearest).getHandle();
|
|
|
|
|
target = ((CraftEntity) nearest).getHandle();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -301,8 +292,8 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
Vector toTarget = getBukkitEntity().getEyeLocation().toVector().subtract(PoI_loc.toVector()).normalize();
|
|
|
|
|
float yaw = (float) Math.atan2(toTarget.getX(), -toTarget.getZ());
|
|
|
|
|
float pitch = (float) Math.atan2(toTarget.getY(), Math.sqrt(toTarget.getX() * toTarget.getX() + toTarget.getZ() * toTarget.getZ()));
|
|
|
|
|
yaw *= 180 / Math.PI;
|
|
|
|
|
pitch *= 180 / Math.PI;
|
|
|
|
|
yaw *= (float) (180 / Math.PI);
|
|
|
|
|
pitch *= (float) (180 / Math.PI);
|
|
|
|
|
setRot(yaw, pitch);
|
|
|
|
|
setYHeadRot(yaw);
|
|
|
|
|
travel(new Vec3(0, 0, 1));
|
|
|
|
@@ -327,8 +318,8 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
Vector toTarget = getBukkitEntity().getEyeLocation().toVector().subtract(((CraftLivingEntity) damager.getBukkitEntity()).getEyeLocation().toVector()).normalize();
|
|
|
|
|
float yaw = (float) Math.atan2(toTarget.getX(), -toTarget.getZ());
|
|
|
|
|
float pitch = (float) Math.atan2(toTarget.getY(), Math.sqrt(toTarget.getX() * toTarget.getX() + toTarget.getZ() * toTarget.getZ()));
|
|
|
|
|
yaw *= 180 / Math.PI;
|
|
|
|
|
pitch *= 180 / Math.PI;
|
|
|
|
|
yaw *= (float) (180 / Math.PI);
|
|
|
|
|
pitch *= (float) (180 / Math.PI);
|
|
|
|
|
setRot(yaw, pitch);
|
|
|
|
|
setYHeadRot(yaw);
|
|
|
|
|
travel(new Vec3(0, 0, 1));
|
|
|
|
@@ -349,55 +340,74 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
private void rangeAttackTarget() {
|
|
|
|
|
if (target == null) return;
|
|
|
|
|
|
|
|
|
|
lookAt(EntityAnchorArgument.Anchor.EYES, target, EntityAnchorArgument.Anchor.EYES);
|
|
|
|
|
double x = getX() - target.getX();
|
|
|
|
|
double y = getY() - target.getY();
|
|
|
|
|
double z = getZ() - target.getZ();
|
|
|
|
|
double r = Math.sqrt(x * x + z * z); // distance in X-Z plane
|
|
|
|
|
|
|
|
|
|
ItemStack itemStackInHand = getItemInHand(InteractionHand.MAIN_HAND);
|
|
|
|
|
Item itemInHand = itemStackInHand.getItem();
|
|
|
|
|
|
|
|
|
|
float pitch = getXRot(); // correcting pitch for distance to target, totally simplified, but it has enough accuracy
|
|
|
|
|
if (itemInHand instanceof BowItem || itemInHand instanceof CrossbowItem) {
|
|
|
|
|
setXRot((float) (pitch - r * ARROW_DIST_COEFF + y * ARROW_HEIGHT_COEFF));
|
|
|
|
|
if (itemInHand instanceof BowItem) {
|
|
|
|
|
if (!isUsingItem()) {
|
|
|
|
|
itemInHand.use(getLevel(), this, InteractionHand.MAIN_HAND);
|
|
|
|
|
}
|
|
|
|
|
if (BowItem.getPowerForTime(getTicksUsingItem()) == 1.0) {
|
|
|
|
|
itemStackInHand.releaseUsing(getLevel(), this, 0);
|
|
|
|
|
stopUsingItem();
|
|
|
|
|
lookAt(EntityAnchorArgument.Anchor.EYES, target, EntityAnchorArgument.Anchor.EYES);
|
|
|
|
|
|
|
|
|
|
// Correcting pitch for distance to target, rough approximation, but it has enough accuracy
|
|
|
|
|
float weaponPitchCorrection = 0;
|
|
|
|
|
float x = (float) (getX() - target.getX());
|
|
|
|
|
float y = (float) (getY() - target.getY());
|
|
|
|
|
float z = (float) (getZ() - target.getZ());
|
|
|
|
|
float r = (float) Math.sqrt(x * x + z * z); // distance in X-Z plane
|
|
|
|
|
|
|
|
|
|
if (itemInHand instanceof BowItem || itemInHand instanceof CrossbowItem)
|
|
|
|
|
weaponPitchCorrection = -r * ARROW_DIST_COEFF + y * ARROW_HEIGHT_COEFF;
|
|
|
|
|
else if (itemInHand instanceof SnowballItem || itemInHand instanceof EggItem)
|
|
|
|
|
weaponPitchCorrection = -r * SNOWBALL_DIST_COEFF + y * SNOWBALL_HEIGHT_COEFF;
|
|
|
|
|
else if (itemInHand instanceof TridentItem)
|
|
|
|
|
weaponPitchCorrection = -r * TRIDENT_DIST_COEFF + y * TRIDENT_DIST_COEFF;
|
|
|
|
|
|
|
|
|
|
// Correcting for target movement speed
|
|
|
|
|
Vec3 targetVel = new Vec3(target.getDeltaMovement().x(), 0, target.getDeltaMovement().z());
|
|
|
|
|
Vec3 lookDir = getLookAngle().normalize();
|
|
|
|
|
|
|
|
|
|
float targetSpeedPitchCorrection, targetSpeedYawCorrection;
|
|
|
|
|
|
|
|
|
|
if (target.invulnerableTime > 10 || target instanceof LargeFireball) {
|
|
|
|
|
targetSpeedPitchCorrection = 0;
|
|
|
|
|
targetSpeedYawCorrection = 0;
|
|
|
|
|
} else {
|
|
|
|
|
targetSpeedPitchCorrection = (float) (-targetVel.dot(lookDir) * r * 0.7);
|
|
|
|
|
targetSpeedYawCorrection = (float) (-targetVel.dot(lookDir.yRot((float) (Math.PI/2))) * r * 1.2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setYRot(getYRot() + targetSpeedYawCorrection);
|
|
|
|
|
setXRot(getXRot() + weaponPitchCorrection + targetSpeedPitchCorrection);
|
|
|
|
|
|
|
|
|
|
if (itemInHand instanceof BowItem) {
|
|
|
|
|
if (!isUsingItem()) {
|
|
|
|
|
itemInHand.use(getLevel(), this, InteractionHand.MAIN_HAND);
|
|
|
|
|
}
|
|
|
|
|
if (BowItem.getPowerForTime(getTicksUsingItem()) == 1.0) {
|
|
|
|
|
itemStackInHand.releaseUsing(getLevel(), this, 0);
|
|
|
|
|
stopUsingItem();
|
|
|
|
|
target = null;
|
|
|
|
|
}
|
|
|
|
|
} else if (itemInHand instanceof CrossbowItem) {
|
|
|
|
|
if (!isUsingItem() || CrossbowItem.isCharged(itemStackInHand)) {
|
|
|
|
|
if (CrossbowItem.isCharged(itemStackInHand))
|
|
|
|
|
target = null;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (!isUsingItem() || CrossbowItem.isCharged(itemStackInHand)) {
|
|
|
|
|
if (CrossbowItem.isCharged(itemStackInHand))
|
|
|
|
|
target = null;
|
|
|
|
|
itemInHand.use(getLevel(), this, InteractionHand.MAIN_HAND);
|
|
|
|
|
}
|
|
|
|
|
if (getTicksUsingItem() >= CrossbowItem.getChargeDuration(itemStackInHand)) {
|
|
|
|
|
itemInHand.releaseUsing(itemStackInHand, getLevel(), this, 0);
|
|
|
|
|
stopUsingItem();
|
|
|
|
|
}
|
|
|
|
|
itemInHand.use(getLevel(), this, InteractionHand.MAIN_HAND);
|
|
|
|
|
}
|
|
|
|
|
if (getTicksUsingItem() >= CrossbowItem.getChargeDuration(itemStackInHand)) {
|
|
|
|
|
itemInHand.releaseUsing(itemStackInHand, getLevel(), this, 0);
|
|
|
|
|
stopUsingItem();
|
|
|
|
|
}
|
|
|
|
|
} else if (itemInHand instanceof SnowballItem || itemInHand instanceof EggItem) {
|
|
|
|
|
setXRot((float) (pitch - r * SNOWBALL_DIST_COEFF + y * SNOWBALL_HEIGHT_COEFF));
|
|
|
|
|
itemInHand.use(getLevel(), this, InteractionHand.MAIN_HAND);
|
|
|
|
|
target = null;
|
|
|
|
|
} else if (itemInHand instanceof TridentItem) {
|
|
|
|
|
setXRot((float) (pitch - r * TRIDENT_DIST_COEFF + y * TRIDENT_HEIGHT_COEFF));
|
|
|
|
|
if (!isUsingItem())
|
|
|
|
|
itemInHand.use(getLevel(), this, InteractionHand.MAIN_HAND);
|
|
|
|
|
if ((float) getTicksUsingItem() >= 10 && !isAutoSpinAttack()) {
|
|
|
|
|
itemInHand.releaseUsing(itemStackInHand, getLevel(), this, 0);
|
|
|
|
|
target = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
setXRot(pitch);
|
|
|
|
|
} else
|
|
|
|
|
target = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CraftLivingEntity getTargetedLivingEntity() {
|
|
|
|
@@ -416,6 +426,12 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
else return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//TODO: find a way to send commands as bots
|
|
|
|
|
/*@Override
|
|
|
|
|
public CommandSourceStack createCommandSourceStack() {
|
|
|
|
|
return new CommandSourceStack((net.minecraft.world.entity.Entity) this, this.position(), this.getRotationVector(), this.level instanceof ServerLevel ? (ServerLevel)this.level : null, this.getPermissionLevel(), this.getName().getString(), this.getDisplayName(), this.level.getServer(), this);
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
public void attack(Entity entity) {
|
|
|
|
|
attack(((CraftEntity) entity).getHandle());
|
|
|
|
|
}
|
|
|
|
@@ -431,6 +447,7 @@ public class DummyPlayer extends ServerPlayer {
|
|
|
|
|
super.die(damagesource);
|
|
|
|
|
setExperienceLevels(0); // idk why we need this but without this bot does not clear xp on death
|
|
|
|
|
setExperiencePoints(0);
|
|
|
|
|
clearFire();
|
|
|
|
|
removeAllEffects();
|
|
|
|
|
getBukkitEntity().setTotalExperience(0); // needed to simplify xp reward calculation
|
|
|
|
|
getServer().execute(new TickTask(getServer().getTickCount(), () -> disconnect("Died")));
|
|
|
|
|