I created a drone in minecraft and gave it some goals which it executes well. Currently I’m having an issue that i cannot for the life of me figure out. so the drone currently shoots an arrow. the arrow will later be a laser but for now i just need the logic to work. So I’m having a couple of problems but the main one is that the arrows when hitting an entity does not always fire the onHitEntity
override…
i can see the arrow spawn. i see the arrow fly towards the creeper. i see the creeper get hit. then the arrow bounces off like the creeper is made of iron and the event never triggers.
Snipped of my class:
public class LaserProjectile extends AbstractArrow {
private static final Logger LOGGER = LogManager.getLogger();
private static final EntityDataAccessor<Integer> CUSTOM_DATA = SynchedEntityData.defineId(LaserProjectile.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> CRITICAL = SynchedEntityData.defineId(LaserProjectile.class, EntityDataSerializers.BOOLEAN);
// Example custom data
private int customData;
public LaserProjectile(EntityType<? extends AbstractArrow> entityType, Level world) {
super(entityType, world);
}
public LaserProjectile(EntityType<? extends AbstractArrow> entityType, double x, double y, double z, Level world) {
super(entityType, x, y, z, world);
}
public LaserProjectile(EntityType<? extends AbstractArrow> entityType, LivingEntity shooter, Level world) {
super(entityType, shooter, world);
}
public LaserProjectile(Level level, LivingEntity shooter) {
super(EntityType.ARROW, shooter, level);
this.setOwner(shooter);
this.setNoGravity(true);
}
@Override
protected void onHitEntity(EntityHitResult ray) {
super.onHitEntity(ray);
LOGGER.debug("hitting enemy!");
DamageSource damageSource = this.damageSources().indirectMagic(this, this.getOwner());
ray.getEntity().hurt(damageSource, 6.0F);
this.discard();
}
@Override
protected void onHitBlock(BlockHitResult ray) {
super.onHitBlock(ray);
this.discard();
}
@Override
protected void tickDespawn() {
if (this.inGroundTime > 60) {
this.discard();
}
}
@Override
protected @NotNull ItemStack getPickupItem() {
return new ItemStack(Items.ARROW);
}
@Override
public void tick() {
super.tick();
if (!this.level().isClientSide && this.getOwner() != null) {
this.setPos(this.getOwner().getX(), this.getOwner().getEyeY(), this.getOwner().getZ());
}
}
@Override
protected void defineSynchedData() {
super.defineSynchedData();
this.entityData.define(CRITICAL, false);
}
@Override
public void addAdditionalSaveData(CompoundTag compound) {
super.addAdditionalSaveData(compound);
compound.putBoolean("Critical", this.isCritArrow());
}
@Override
public void readAdditionalSaveData(CompoundTag compound) {
super.readAdditionalSaveData(compound);
this.setCritArrow(compound.getBoolean("Critical"));
}
public boolean isCritArrow() {
return this.entityData.get(CRITICAL);
}
public void setCritArrow(boolean critical) {
this.entityData.set(CRITICAL, critical);
}
}
and this is the goal class i created for it:
public class AttackHostileMobsGoal extends Goal {
private static final Logger LOGGER = LogManager.getLogger();
private static final int ATTACK_COOLDOWN_TICKS = 200; // Cooldown in ticks (1 second)
private final PathfinderMob entity;
private final double attackRange;
private final double followSpeed;
private LivingEntity target;
private int ticksSinceLastAttack = ATTACK_COOLDOWN_TICKS;
public AttackHostileMobsGoal(PathfinderMob entity, double attackRange, double followSpeed) {
this.entity = entity;
this.attackRange = attackRange;
this.followSpeed = followSpeed;
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
}
@Override
public boolean canUse() {
List<Monster> nearbyHostileMobs = this.entity.level().getEntitiesOfClass(Monster.class, this.entity.getBoundingBox().inflate(attackRange));
if (!nearbyHostileMobs.isEmpty()) {
this.target = nearbyHostileMobs.get(0);
return true;
}
return false;
}
@Override
public boolean canContinueToUse() {
return this.target != null && this.target.isAlive() && this.entity.distanceToSqr(this.target) <= attackRange * attackRange;
}
@Override
public void start() {
this.entity.getNavigation().moveTo(this.target, this.followSpeed);
}
@Override
public void stop() {
this.target = null;
this.entity.getNavigation().stop();
}
@Override
public void tick() {
if (this.target != null && this.entity.distanceToSqr(this.target) <= attackRange * attackRange) {
this.entity.getLookControl().setLookAt(this.target, 30.0F, 30.0F);
if (ticksSinceLastAttack >= ATTACK_COOLDOWN_TICKS) {
attackWithLaser(this.target);
ticksSinceLastAttack = 0; // Reset cooldown
} else {
ticksSinceLastAttack++;
}
} else {
this.entity.getNavigation().moveTo(this.target, this.followSpeed);
}
}
private void attackWithLaser(LivingEntity target) {
// Calculate the direction from the entity to the target
Vec3 direction = new Vec3(target.getX() - this.entity.getX(), target.getEyeY() - this.entity.getEyeY(), target.getZ() - this.entity.getZ());
double distance = direction.length(); // length is used instead of sqrt(x*x + y*y + z*z)
// Normalize the direction vector
direction = direction.normalize();
// Create and initialize the laser projectile
LaserProjectile laser = new LaserProjectile(this.entity.level(), this.entity);
double startX = this.entity.getX() + direction.x * 1.0D;
double startY = this.entity.getEyeY() + direction.y * 1.0D;
double startZ = this.entity.getZ() + direction.z * 1.0D;
//LOGGER.debug("Entity Position: X=" + this.entity.getX() + ", Y=" + this.entity.getEyeY() + ", Z=" + this.entity.getZ());
//LOGGER.debug("Target Position: X=" + target.getX() + ", Y=" + target.getEyeY() + ", Z=" + target.getZ());
// Shoot the projectile with a specified speed and no gravity
laser.shoot(direction.x, direction.y, direction.z, 1.5F, 0.0F);
// Set the starting position of the projectile
laser.setPos(startX, startY, startZ);
// Spawn the projectile in the world
this.entity.level().addFreshEntity(laser);
}
}
does anyone know what im doing wrong?