diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index a61275d84..80e0e239f 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -671,7 +671,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer { EntityVelocityEvent entityVelocityEvent = new EntityVelocityEvent(this, velocity); callCancellableEvent(EntityVelocityEvent.class, entityVelocityEvent, () -> { this.velocity.copy(entityVelocityEvent.getVelocity()); - sendPacketToViewers(getVelocityPacket()); + sendPacketToViewersAndSelf(getVelocityPacket()); }); } diff --git a/src/main/java/net/minestom/server/entity/EntityCreature.java b/src/main/java/net/minestom/server/entity/EntityCreature.java index 29b8cd3c8..08d92e745 100644 --- a/src/main/java/net/minestom/server/entity/EntityCreature.java +++ b/src/main/java/net/minestom/server/entity/EntityCreature.java @@ -109,7 +109,7 @@ public abstract class EntityCreature extends LivingEntity { // Execute tick for the goal selector if (currentGoalSelector != null) { - currentGoalSelector.tick(); + currentGoalSelector.tick(time); } } diff --git a/src/main/java/net/minestom/server/entity/ai/GoalSelector.java b/src/main/java/net/minestom/server/entity/ai/GoalSelector.java index 3adc651d5..593d54fef 100644 --- a/src/main/java/net/minestom/server/entity/ai/GoalSelector.java +++ b/src/main/java/net/minestom/server/entity/ai/GoalSelector.java @@ -25,8 +25,10 @@ public abstract class GoalSelector { /** * Called every tick when this {@link GoalSelector} is running + * + * @param time the time of the update in milliseconds */ - public abstract void tick(); + public abstract void tick(long time); /** * Whether or not this {@link GoalSelector} should end. diff --git a/src/main/java/net/minestom/server/entity/ai/goal/DoNothingGoal.java b/src/main/java/net/minestom/server/entity/ai/goal/DoNothingGoal.java index e2f76f4f3..fac5017ab 100644 --- a/src/main/java/net/minestom/server/entity/ai/goal/DoNothingGoal.java +++ b/src/main/java/net/minestom/server/entity/ai/goal/DoNothingGoal.java @@ -48,7 +48,7 @@ public class DoNothingGoal extends GoalSelector { } @Override - public void tick() { + public void tick(long time) { } } diff --git a/src/main/java/net/minestom/server/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minestom/server/entity/ai/goal/EatBlockGoal.java index 77d5b430f..b4e3f5166 100644 --- a/src/main/java/net/minestom/server/entity/ai/goal/EatBlockGoal.java +++ b/src/main/java/net/minestom/server/entity/ai/goal/EatBlockGoal.java @@ -55,7 +55,7 @@ public class EatBlockGoal extends GoalSelector { } @Override - public void tick() { + public void tick(long time) { this.eatAnimationTick = Math.max(0, this.eatAnimationTick - 1); if (this.eatAnimationTick != 4) { return; diff --git a/src/main/java/net/minestom/server/entity/ai/goal/FollowTargetGoal.java b/src/main/java/net/minestom/server/entity/ai/goal/FollowTargetGoal.java index 0a89e9e75..c8ea28530 100644 --- a/src/main/java/net/minestom/server/entity/ai/goal/FollowTargetGoal.java +++ b/src/main/java/net/minestom/server/entity/ai/goal/FollowTargetGoal.java @@ -7,8 +7,6 @@ import net.minestom.server.utils.Position; public class FollowTargetGoal extends GoalSelector { - private Position lastPath; - public FollowTargetGoal(EntityCreature entityCreature) { super(entityCreature); } @@ -29,15 +27,15 @@ public class FollowTargetGoal extends GoalSelector { return; } - if (lastPath == null || lastPath.equals(targetPosition)) { + if (entityCreature.getPathPosition() == null || + (!entityCreature.getPathPosition().isSimilar(targetPosition))) { entityCreature.setPathTo(targetPosition); - lastPath = targetPosition; } } } @Override - public void tick() { + public void tick(long time) { } diff --git a/src/main/java/net/minestom/server/entity/ai/goal/MeleeAttackGoal.java b/src/main/java/net/minestom/server/entity/ai/goal/MeleeAttackGoal.java new file mode 100644 index 000000000..9d5f14cae --- /dev/null +++ b/src/main/java/net/minestom/server/entity/ai/goal/MeleeAttackGoal.java @@ -0,0 +1,68 @@ +package net.minestom.server.entity.ai.goal; + +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityCreature; +import net.minestom.server.entity.ai.GoalSelector; +import net.minestom.server.utils.Position; +import net.minestom.server.utils.time.CooldownUtils; +import net.minestom.server.utils.time.TimeUnit; + +public class MeleeAttackGoal extends GoalSelector { + + private long lastHit; + private int delay; + private TimeUnit timeUnit; + + /** + * @param entityCreature the entity to add the goal to + * @param delay the delay between each attacks + * @param timeUnit the unit of the delay + */ + public MeleeAttackGoal(EntityCreature entityCreature, int delay, TimeUnit timeUnit) { + super(entityCreature); + this.delay = delay; + this.timeUnit = timeUnit; + } + + @Override + public boolean shouldStart() { + return entityCreature.getTarget() != null; + } + + @Override + public void start() { + final Position targetPosition = entityCreature.getTarget().getPosition(); + entityCreature.setPathTo(targetPosition); + } + + @Override + public void tick(long time) { + final Entity target = entityCreature.getTarget(); + if (target != null) { + + if (entityCreature.getBoundingBox().intersect(target)) { + if (!CooldownUtils.hasCooldown(time, lastHit, timeUnit, delay)) { + entityCreature.attack(target, true); + this.lastHit = time; + } + return; + } + + final Position pathPosition = entityCreature.getPathPosition(); + final Position targetPosition = target.getPosition(); + if (pathPosition == null || !pathPosition.isSimilar(targetPosition)) { + entityCreature.setPathTo(targetPosition); + } + } + } + + @Override + public boolean shouldEnd() { + return entityCreature.getTarget() == null; + } + + @Override + public void end() { + + } +} diff --git a/src/main/java/net/minestom/server/entity/ai/goal/RandomLookAroundGoal.java b/src/main/java/net/minestom/server/entity/ai/goal/RandomLookAroundGoal.java index 90e10e5bf..55bbcb7a0 100644 --- a/src/main/java/net/minestom/server/entity/ai/goal/RandomLookAroundGoal.java +++ b/src/main/java/net/minestom/server/entity/ai/goal/RandomLookAroundGoal.java @@ -67,7 +67,7 @@ public class RandomLookAroundGoal extends GoalSelector { } @Override - public void tick() { + public void tick(long time) { --lookTime; entityCreature.setView(entityCreature.getPosition().clone().setDirection(lookDirection)); } diff --git a/src/main/java/net/minestom/server/entity/ai/goal/RandomStrollGoal.java b/src/main/java/net/minestom/server/entity/ai/goal/RandomStrollGoal.java index 00259c680..836a4fdfd 100644 --- a/src/main/java/net/minestom/server/entity/ai/goal/RandomStrollGoal.java +++ b/src/main/java/net/minestom/server/entity/ai/goal/RandomStrollGoal.java @@ -44,7 +44,7 @@ public class RandomStrollGoal extends GoalSelector { } @Override - public void tick() { + public void tick(long time) { } diff --git a/src/main/java/net/minestom/server/utils/Position.java b/src/main/java/net/minestom/server/utils/Position.java index 8e5e2e218..022664593 100644 --- a/src/main/java/net/minestom/server/utils/Position.java +++ b/src/main/java/net/minestom/server/utils/Position.java @@ -189,6 +189,16 @@ public class Position { Float.compare(position.pitch, pitch) == 0; } + /** + * Check it two positions are similar (x/y/z) + * + * @param position the position to compare + * @return true if the two positions are similar + */ + public boolean isSimilar(Position position) { + return position.x == x && position.y == y && position.z == z; + } + @Override public int hashCode() { return Objects.hash(x, y, z, yaw, pitch);