diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index e66b66ae0..6dde0c1f8 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -307,16 +307,6 @@ public class Entity implements Viewable, Tickable, EventHandler, Da sendPacketToViewersAndSelf(entityRotationPacket); } - /** - * Changes the view of the entity. - * Only the yaw and pitch are used. - * - * @param position the new view - */ - public void setView(@NotNull Position position) { - setView(position.getYaw(), position.getPitch()); - } - /** * When set to true, the entity will automatically get new viewers when they come too close. * This can be use to have complete control over which player can see it, without having to deal with @@ -485,9 +475,7 @@ public class Entity implements Viewable, Tickable, EventHandler, Da } } - sendPositionUpdate(false); final boolean isNettyClient = PlayerUtils.isNettyClient(this); - // Entity tick { diff --git a/src/main/java/net/minestom/server/entity/EntityProjectile.java b/src/main/java/net/minestom/server/entity/EntityProjectile.java index 93ba38001..a39d50598 100644 --- a/src/main/java/net/minestom/server/entity/EntityProjectile.java +++ b/src/main/java/net/minestom/server/entity/EntityProjectile.java @@ -7,10 +7,8 @@ import net.minestom.server.event.entity.EntityShootEvent; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; -import net.minestom.server.utils.BlockPosition; -import net.minestom.server.utils.Position; -import net.minestom.server.utils.Vector; import net.minestom.server.utils.coordinate.Point; +import net.minestom.server.utils.coordinate.Pos; import net.minestom.server.utils.coordinate.Vec; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -130,7 +128,7 @@ public class EntityProjectile extends Entity { * @return if an arrow is stuck in block / hit an entity. */ @SuppressWarnings("ConstantConditions") - private boolean isStuck(Point pos, Point posNow) { + private boolean isStuck(Pos pos, Pos posNow) { if (pos.samePoint(posNow)) { return true; } @@ -144,25 +142,21 @@ public class EntityProjectile extends Entity { For each point we will be checking blocks and entities we're in. */ double part = .25D; // half of the bounding box - Vector dir = posNow.toVector().subtract(pos.toVector()); + final var dir = posNow.sub(pos).asVec(); int parts = (int) Math.ceil(dir.length() / part); - Position direction = dir.normalize().multiply(part).toPosition(); + final var direction = dir.normalize().mul(part).asPosition(); for (int i = 0; i < parts; ++i) { // If we're at last part, we can't just add another direction-vector, because we can exceed end point. if (i == parts - 1) { - pos.setX(posNow.getX()); - pos.setY(posNow.getY()); - pos.setZ(posNow.getZ()); + pos = posNow; } else { - pos.add(direction); + pos = pos.add(direction); } - BlockPosition bpos = pos.toBlockPosition(); - Block block = instance.getBlock(bpos.getX(), bpos.getY() - 1, bpos.getZ()); + Block block = instance.getBlock(pos.sub(0, 1, 0)); if (!block.isAir() && !block.isLiquid()) { teleport(pos); return true; } - Chunk currentChunk = instance.getChunkAt(pos); if (currentChunk != chunk) { chunk = currentChunk; @@ -178,8 +172,9 @@ public class EntityProjectile extends Entity { if (getAliveTicks() < 3) { continue; } + final Pos finalPos = pos; Optional victimOptional = entities.stream() - .filter(entity -> entity.getBoundingBox().intersect(pos)) + .filter(entity -> entity.getBoundingBox().intersect(finalPos)) .findAny(); if (victimOptional.isPresent()) { LivingEntity victim = (LivingEntity) victimOptional.get(); 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 af0e39ba5..d0f80ce60 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 @@ -2,7 +2,6 @@ package net.minestom.server.entity.ai.goal; import net.minestom.server.entity.EntityCreature; import net.minestom.server.entity.ai.GoalSelector; -import net.minestom.server.utils.Vector; import net.minestom.server.utils.coordinate.Vec; import org.jetbrains.annotations.NotNull; @@ -69,7 +68,7 @@ public class RandomLookAroundGoal extends GoalSelector { @Override public void tick(long time) { --lookTime; - entityCreature.setView(entityCreature.getPosition().clone().setDirection(lookDirection)); + entityCreature.teleport(entityCreature.getPosition().withDirection(lookDirection)); } @Override diff --git a/src/main/java/net/minestom/server/utils/block/BlockIterator.java b/src/main/java/net/minestom/server/utils/block/BlockIterator.java index 9ff61db06..c3191ac45 100644 --- a/src/main/java/net/minestom/server/utils/block/BlockIterator.java +++ b/src/main/java/net/minestom/server/utils/block/BlockIterator.java @@ -55,9 +55,8 @@ public class BlockIterator implements Iterator { public BlockIterator(@NotNull Vec start, @NotNull Vec direction, double yOffset, int maxDistance) { this.maxDistance = maxDistance; - Vector startClone = start.clone(); - startClone.setY(startClone.getY() + yOffset); + Vec startClone = start.withY(y -> y+yOffset); currentDistance = 0; @@ -69,7 +68,7 @@ public class BlockIterator implements Iterator { double secondPosition = 0; double thirdPosition = 0; - BlockPosition startBlock = new BlockPosition(floor(startClone.getX()), floor(startClone.getY()), floor(startClone.getZ())); + Vec startBlock = startClone.with(Vec.Operator.FLOOR); if (getXLength(direction) > mainDirection) { mainFace = getXFace(direction); @@ -133,18 +132,18 @@ public class BlockIterator implements Iterator { thirdError = -thirdStep + 1; } - BlockPosition lastBlock; + Vec lastBlock; - lastBlock = startBlock.getRelative(mainFace.getOppositeFace()); + lastBlock = startBlock.relative(mainFace.getOppositeFace()); if (secondError < 0) { secondError += gridSize; - lastBlock = lastBlock.getRelative(secondFace.getOppositeFace()); + lastBlock = lastBlock.relative(secondFace.getOppositeFace()); } if (thirdError < 0) { thirdError += gridSize; - lastBlock = lastBlock.getRelative(thirdFace.getOppositeFace()); + lastBlock = lastBlock.relative(thirdFace.getOppositeFace()); } // This means that when the variables are positive, it means that the coord=1 boundary has been crossed @@ -179,44 +178,44 @@ public class BlockIterator implements Iterator { return a.x() == b.x() && a.y() == b.y() && a.z() == b.z(); } - private BlockFace getXFace(@NotNull Vector direction) { - return ((direction.getX() > 0) ? BlockFace.EAST : BlockFace.WEST); + private BlockFace getXFace(@NotNull Point direction) { + return ((direction.x() > 0) ? BlockFace.EAST : BlockFace.WEST); } - private BlockFace getYFace(@NotNull Vector direction) { - return ((direction.getY() > 0) ? BlockFace.TOP : BlockFace.BOTTOM); + private BlockFace getYFace(@NotNull Point direction) { + return ((direction.y() > 0) ? BlockFace.TOP : BlockFace.BOTTOM); } - private BlockFace getZFace(@NotNull Vector direction) { - return ((direction.getZ() > 0) ? BlockFace.SOUTH : BlockFace.NORTH); + private BlockFace getZFace(@NotNull Point direction) { + return ((direction.z() > 0) ? BlockFace.SOUTH : BlockFace.NORTH); } - private double getXLength(@NotNull Vector direction) { - return Math.abs(direction.getX()); + private double getXLength(@NotNull Point direction) { + return Math.abs(direction.x()); } - private double getYLength(@NotNull Vector direction) { - return Math.abs(direction.getY()); + private double getYLength(@NotNull Point direction) { + return Math.abs(direction.y()); } - private double getZLength(@NotNull Vector direction) { - return Math.abs(direction.getZ()); + private double getZLength(@NotNull Point direction) { + return Math.abs(direction.z()); } private double getPosition(double direction, double position, int blockPosition) { return direction > 0 ? (position - blockPosition) : (blockPosition + 1 - position); } - private double getXPosition(@NotNull Vector direction, @NotNull Vector position, @NotNull BlockPosition block) { - return getPosition(direction.getX(), position.getX(), block.getX()); + private double getXPosition(@NotNull Point direction, @NotNull Point position, @NotNull Point block) { + return getPosition(direction.x(), position.x(), block.blockX()); } - private double getYPosition(@NotNull Vector direction, @NotNull Vector position, @NotNull BlockPosition block) { - return getPosition(direction.getY(), position.getY(), block.getY()); + private double getYPosition(@NotNull Point direction, @NotNull Point position, @NotNull Point block) { + return getPosition(direction.y(), position.y(), block.blockY()); } - private double getZPosition(@NotNull Vector direction, @NotNull Vector position, @NotNull BlockPosition block) { - return getPosition(direction.getZ(), position.getZ(), block.getZ()); + private double getZPosition(@NotNull Point direction, @NotNull Point position, @NotNull Point block) { + return getPosition(direction.z(), position.z(), block.blockZ()); } /** @@ -232,7 +231,7 @@ public class BlockIterator implements Iterator { * unloaded chunks. A value of 0 indicates no limit */ public BlockIterator(@NotNull Pos pos, double yOffset, int maxDistance) { - this(pos.toVector(), pos.getDirection(), yOffset, maxDistance); + this(pos.asVec(), pos.direction(), yOffset, maxDistance); } /** @@ -246,7 +245,7 @@ public class BlockIterator implements Iterator { */ public BlockIterator(@NotNull Pos pos, double yOffset) { - this(pos.toVector(), pos.getDirection(), yOffset, 0); + this(pos.asVec(), pos.direction(), yOffset, 0); } /** @@ -305,7 +304,7 @@ public class BlockIterator implements Iterator { */ @Override @NotNull - public BlockPosition next() throws NoSuchElementException { + public Point next() throws NoSuchElementException { scan(); if (currentBlock <= -1) { throw new NoSuchElementException(); @@ -337,29 +336,29 @@ public class BlockIterator implements Iterator { thirdError += thirdStep; if (secondError > 0 && thirdError > 0) { - blockQueue[2] = blockQueue[0].getRelative(mainFace); + blockQueue[2] = blockQueue[0].relative(mainFace); if (((long) secondStep) * ((long) thirdError) < ((long) thirdStep) * ((long) secondError)) { - blockQueue[1] = blockQueue[2].getRelative(secondFace); - blockQueue[0] = blockQueue[1].getRelative(thirdFace); + blockQueue[1] = blockQueue[2].relative(secondFace); + blockQueue[0] = blockQueue[1].relative(thirdFace); } else { - blockQueue[1] = blockQueue[2].getRelative(thirdFace); - blockQueue[0] = blockQueue[1].getRelative(secondFace); + blockQueue[1] = blockQueue[2].relative(thirdFace); + blockQueue[0] = blockQueue[1].relative(secondFace); } thirdError -= gridSize; secondError -= gridSize; currentBlock = 2; } else if (secondError > 0) { - blockQueue[1] = blockQueue[0].getRelative(mainFace); - blockQueue[0] = blockQueue[1].getRelative(secondFace); + blockQueue[1] = blockQueue[0].relative(mainFace); + blockQueue[0] = blockQueue[1].relative(secondFace); secondError -= gridSize; currentBlock = 1; } else if (thirdError > 0) { - blockQueue[1] = blockQueue[0].getRelative(mainFace); - blockQueue[0] = blockQueue[1].getRelative(thirdFace); + blockQueue[1] = blockQueue[0].relative(mainFace); + blockQueue[0] = blockQueue[1].relative(thirdFace); thirdError -= gridSize; currentBlock = 1; } else { - blockQueue[0] = blockQueue[0].getRelative(mainFace); + blockQueue[0] = blockQueue[0].relative(mainFace); currentBlock = 0; } } diff --git a/src/main/java/net/minestom/server/utils/coordinate/Point.java b/src/main/java/net/minestom/server/utils/coordinate/Point.java index eb4a5917b..f02b6d8a8 100644 --- a/src/main/java/net/minestom/server/utils/coordinate/Point.java +++ b/src/main/java/net/minestom/server/utils/coordinate/Point.java @@ -1,5 +1,6 @@ package net.minestom.server.utils.coordinate; +import net.minestom.server.instance.block.BlockFace; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.ApiStatus; @@ -110,6 +111,25 @@ public interface Point { @Contract(pure = true) @NotNull Point div(double value); + @Contract(pure = true) + default @NotNull Point relative(@NotNull BlockFace face) { + switch (face) { + case BOTTOM: + return sub(0, 1, 0); + case TOP: + return add(0, 1, 0); + case NORTH: + return sub(0, 0, 1); + case SOUTH: + return add(0, 0, 1); + case WEST: + return sub(1, 0, 0); + case EAST: + return add(1, 0, 0); + } + return this; // should never be called + } + /** * Gets the distance between this point and another. The value of this * method is not cached and uses a costly square-root function, so do not diff --git a/src/main/java/net/minestom/server/utils/coordinate/Pos.java b/src/main/java/net/minestom/server/utils/coordinate/Pos.java index 3cff502e5..e91848172 100644 --- a/src/main/java/net/minestom/server/utils/coordinate/Pos.java +++ b/src/main/java/net/minestom/server/utils/coordinate/Pos.java @@ -1,5 +1,7 @@ package net.minestom.server.utils.coordinate; +import net.minestom.server.instance.block.BlockFace; +import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.Position; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -57,6 +59,32 @@ public final class Pos implements Point { return new Pos(x, y, z, yaw, pitch); } + /** + * Sets the yaw and pitch to point + * in the direction of the point. + */ + @Contract(pure = true) + public @NotNull Pos withDirection(@NotNull Point point) { + /* + * Sin = Opp / Hyp + * Cos = Adj / Hyp + * Tan = Opp / Adj + * + * x = -Opp + * z = Adj + */ + final double _2PI = 2 * Math.PI; + final double x = point.x(); + final double z = point.z(); + if (x == 0 && z == 0) { + return withPitch(point.y() > 0 ? -90f : 90f); + } + final double theta = Math.atan2(-x, z); + final double xz = Math.sqrt(MathUtils.square(x) + MathUtils.square(z)); + return withView((float) Math.toDegrees((theta + _2PI) % _2PI), + (float) Math.toDegrees(Math.atan(-point.y() / xz))); + } + @Contract(pure = true) public @NotNull Pos withYaw(float yaw) { return new Pos(x, y, z, yaw, pitch); @@ -223,6 +251,11 @@ public final class Pos implements Point { return div(value, value, value); } + @Override + public @NotNull Pos relative(@NotNull BlockFace face) { + return (Pos) Point.super.relative(face); + } + @Contract(pure = true) public float yaw() { return yaw; diff --git a/src/main/java/net/minestom/server/utils/coordinate/Vec.java b/src/main/java/net/minestom/server/utils/coordinate/Vec.java index 684974688..2e734a249 100644 --- a/src/main/java/net/minestom/server/utils/coordinate/Vec.java +++ b/src/main/java/net/minestom/server/utils/coordinate/Vec.java @@ -1,5 +1,6 @@ package net.minestom.server.utils.coordinate; +import net.minestom.server.instance.block.BlockFace; import net.minestom.server.utils.MathUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -158,6 +159,11 @@ public final class Vec implements Point { return div(value, value, value); } + @Override + public @NotNull Vec relative(@NotNull BlockFace face) { + return (Vec) Point.super.relative(face); + } + @Contract(pure = true) public @NotNull Vec neg() { return new Vec(-x, -y, -z); @@ -401,6 +407,12 @@ public final class Vec implements Point { Math.abs(z) < 1E-6 ? 0 : z ); + Operator FLOOR = (x, y, z) -> new Vec( + MathUtils.floor(x), + MathUtils.floor(y), + MathUtils.floor(z) + ); + @NotNull Vec apply(double x, double y, double z); } diff --git a/src/main/java/net/minestom/server/utils/location/RelativeLocation.java b/src/main/java/net/minestom/server/utils/location/RelativeLocation.java index 1a2843036..7b647c66a 100644 --- a/src/main/java/net/minestom/server/utils/location/RelativeLocation.java +++ b/src/main/java/net/minestom/server/utils/location/RelativeLocation.java @@ -44,13 +44,13 @@ public abstract class RelativeLocation { */ public T from(@Nullable Entity entity) { final var entityPosition = entity != null ? entity.getPosition() : Pos.ZERO; - return from(entityPosition); + return null;//from(entityPosition); FIXME } @ApiStatus.Experimental public T fromView(@Nullable Entity entity) { final var entityPosition = entity != null ? entity.getPosition() : Pos.ZERO; - return fromView(entityPosition); + return null;//fromView(entityPosition); FIXME } /** diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 1e9273101..822d15fa2 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -51,7 +51,7 @@ public class PlayerInit { final Entity source = event.getEntity(); final Entity entity = event.getTarget(); - entity.takeKnockback(0.4f, Math.sin(source.getPosition().getYaw() * 0.017453292), -Math.cos(source.getPosition().getYaw() * 0.017453292)); + entity.takeKnockback(0.4f, Math.sin(source.getPosition().yaw() * 0.017453292), -Math.cos(source.getPosition().yaw() * 0.017453292)); if (entity instanceof Player) { Player target = (Player) entity; diff --git a/src/test/java/demo/commands/ShootCommand.java b/src/test/java/demo/commands/ShootCommand.java index 3d8cbd17b..4c4d8d198 100644 --- a/src/test/java/demo/commands/ShootCommand.java +++ b/src/test/java/demo/commands/ShootCommand.java @@ -52,11 +52,11 @@ public class ShootCommand extends Command { default: return; } - var pos = player.getPosition().clone().add(0D, player.getEyeHeight(), 0D); + var pos = player.getPosition().add(0D, player.getEyeHeight(), 0D); //noinspection ConstantConditions - It should be impossible to execute a command without being in an instance projectile.setInstance(player.getInstance(), pos); - var dir = pos.getDirection().multiply(30D); - pos = pos.clone().add(dir.getX(), dir.getY(), dir.getZ()); + var dir = pos.direction().mul(30D); + pos = pos.add(dir); projectile.shoot(pos, 1D, 0D); } } diff --git a/src/test/java/demo/commands/TeleportCommand.java b/src/test/java/demo/commands/TeleportCommand.java index 27888b9ff..f67f8609f 100644 --- a/src/test/java/demo/commands/TeleportCommand.java +++ b/src/test/java/demo/commands/TeleportCommand.java @@ -8,6 +8,7 @@ import net.minestom.server.command.builder.CommandContext; import net.minestom.server.command.builder.arguments.ArgumentType; import net.minestom.server.entity.Player; import net.minestom.server.utils.Position; +import net.minestom.server.utils.coordinate.Pos; import net.minestom.server.utils.location.RelativeVec; public class TeleportCommand extends Command { @@ -40,7 +41,7 @@ public class TeleportCommand extends Command { final RelativeVec relativeVec = context.get("pos"); final Position position = relativeVec.from(player).toPosition(); - player.teleport(position); + player.teleport(new Pos(position)); player.sendMessage(Component.text("You have been teleported to " + position)); } diff --git a/src/test/java/demo/entity/ChickenCreature.java b/src/test/java/demo/entity/ChickenCreature.java index 4d4d05a50..04af60dfc 100644 --- a/src/test/java/demo/entity/ChickenCreature.java +++ b/src/test/java/demo/entity/ChickenCreature.java @@ -8,7 +8,7 @@ import net.minestom.server.entity.LivingEntity; import net.minestom.server.entity.ai.goal.RandomStrollGoal; import net.minestom.server.entity.damage.DamageType; import net.minestom.server.event.entity.EntityAttackEvent; -import net.minestom.server.utils.Vector; +import net.minestom.server.utils.coordinate.Vec; public class ChickenCreature extends EntityCreature { @@ -43,12 +43,10 @@ public class ChickenCreature extends EntityCreature { addEventCallback(EntityAttackEvent.class, event -> { //System.out.println("CALL ATTACK"); LivingEntity entity = (LivingEntity) event.getTarget(); - Vector velocity = getPosition().clone().getDirection().multiply(6); - velocity.setY(4f); + Vec velocity = getPosition().direction().mul(6).withY(4); entity.damage(DamageType.fromEntity(this), -1); entity.setVelocity(velocity); }); - } @Override