diff --git a/src/main/java/net/minestom/server/collision/BoundingBox.java b/src/main/java/net/minestom/server/collision/BoundingBox.java index 447d37430..7aca98339 100644 --- a/src/main/java/net/minestom/server/collision/BoundingBox.java +++ b/src/main/java/net/minestom/server/collision/BoundingBox.java @@ -7,7 +7,9 @@ import net.minestom.server.entity.Entity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; /** @@ -18,13 +20,42 @@ public class BoundingBox { private final Entity entity; private final double x, y, z; - private volatile Pos lastPosition; - private List bottomFace; - private List topFace; - private List leftFace; - private List rightFace; - private List frontFace; - private List backFace; + private final CachedFace bottomFace = new CachedFace(() -> List.of( + new Vec(getMinX(), getMinY(), getMinZ()), + new Vec(getMaxX(), getMinY(), getMinZ()), + new Vec(getMaxX(), getMinY(), getMaxZ()), + new Vec(getMinX(), getMinY(), getMaxZ()) + )); + private final CachedFace topFace = new CachedFace(() -> List.of( + new Vec(getMinX(), getMaxY(), getMinZ()), + new Vec(getMaxX(), getMaxY(), getMinZ()), + new Vec(getMaxX(), getMaxY(), getMaxZ()), + new Vec(getMinX(), getMaxY(), getMaxZ()) + )); + private final CachedFace leftFace = new CachedFace(() -> List.of( + new Vec(getMinX(), getMinY(), getMinZ()), + new Vec(getMinX(), getMaxY(), getMinZ()), + new Vec(getMinX(), getMaxY(), getMaxZ()), + new Vec(getMinX(), getMinY(), getMaxZ()) + )); + private final CachedFace rightFace = new CachedFace(() -> List.of( + new Vec(getMaxX(), getMinY(), getMinZ()), + new Vec(getMaxX(), getMaxY(), getMinZ()), + new Vec(getMaxX(), getMaxY(), getMaxZ()), + new Vec(getMaxX(), getMinY(), getMaxZ()) + )); + private final CachedFace frontFace = new CachedFace(() -> List.of( + new Vec(getMinX(), getMinY(), getMinZ()), + new Vec(getMaxX(), getMinY(), getMinZ()), + new Vec(getMaxX(), getMaxY(), getMinZ()), + new Vec(getMinX(), getMaxY(), getMinZ()) + )); + private final CachedFace backFace = new CachedFace(() -> List.of( + new Vec(getMinX(), getMinY(), getMaxZ()), + new Vec(getMaxX(), getMinY(), getMaxZ()), + new Vec(getMaxX(), getMaxY(), getMaxZ()), + new Vec(getMinX(), getMaxY(), getMaxZ()) + )); /** * Creates a {@link BoundingBox} linked to an {@link Entity} and with a specific size. @@ -320,12 +351,7 @@ public class BoundingBox { * @return the points at the bottom of the {@link BoundingBox} */ public @NotNull List getBottomFace() { - this.bottomFace = get(bottomFace, () -> - List.of(new Vec(getMinX(), getMinY(), getMinZ()), - new Vec(getMaxX(), getMinY(), getMinZ()), - new Vec(getMaxX(), getMinY(), getMaxZ()), - new Vec(getMinX(), getMinY(), getMaxZ()))); - return bottomFace; + return bottomFace.get(); } /** @@ -334,12 +360,7 @@ public class BoundingBox { * @return the points at the top of the {@link BoundingBox} */ public @NotNull List getTopFace() { - this.topFace = get(topFace, () -> - List.of(new Vec(getMinX(), getMaxY(), getMinZ()), - new Vec(getMaxX(), getMaxY(), getMinZ()), - new Vec(getMaxX(), getMaxY(), getMaxZ()), - new Vec(getMinX(), getMaxY(), getMaxZ()))); - return topFace; + return topFace.get(); } /** @@ -348,12 +369,7 @@ public class BoundingBox { * @return the points on the left face of the {@link BoundingBox} */ public @NotNull List getLeftFace() { - this.leftFace = get(leftFace, () -> - List.of(new Vec(getMinX(), getMinY(), getMinZ()), - new Vec(getMinX(), getMaxY(), getMinZ()), - new Vec(getMinX(), getMaxY(), getMaxZ()), - new Vec(getMinX(), getMinY(), getMaxZ()))); - return leftFace; + return leftFace.get(); } /** @@ -362,12 +378,7 @@ public class BoundingBox { * @return the points on the right face of the {@link BoundingBox} */ public @NotNull List getRightFace() { - this.rightFace = get(rightFace, () -> - List.of(new Vec(getMaxX(), getMinY(), getMinZ()), - new Vec(getMaxX(), getMaxY(), getMinZ()), - new Vec(getMaxX(), getMaxY(), getMaxZ()), - new Vec(getMaxX(), getMinY(), getMaxZ()))); - return rightFace; + return rightFace.get(); } /** @@ -376,12 +387,7 @@ public class BoundingBox { * @return the points at the front of the {@link BoundingBox} */ public @NotNull List getFrontFace() { - this.frontFace = get(frontFace, () -> - List.of(new Vec(getMinX(), getMinY(), getMinZ()), - new Vec(getMaxX(), getMinY(), getMinZ()), - new Vec(getMaxX(), getMaxY(), getMinZ()), - new Vec(getMinX(), getMaxY(), getMinZ()))); - return frontFace; + return frontFace.get(); } /** @@ -390,12 +396,7 @@ public class BoundingBox { * @return the points at the back of the {@link BoundingBox} */ public @NotNull List getBackFace() { - this.backFace = get(backFace, () -> List.of( - new Vec(getMinX(), getMinY(), getMaxZ()), - new Vec(getMaxX(), getMinY(), getMaxZ()), - new Vec(getMaxX(), getMaxY(), getMaxZ()), - new Vec(getMinX(), getMaxY(), getMaxZ()))); - return backFace; + return backFace.get(); } @Override @@ -410,18 +411,42 @@ public class BoundingBox { return result; } - private @NotNull List get(@Nullable List face, Supplier> vecSupplier) { - final var lastPos = this.lastPosition; - final var entityPos = entity.getPosition(); - if (face != null && lastPos != null && lastPos.samePoint(entityPos)) { - return face; - } - this.lastPosition = entityPos; - return vecSupplier.get(); - } - private enum Axis { X, Y, Z } + private class CachedFace { + + private final AtomicReference<@Nullable PositionedPoints> reference = new AtomicReference<>(null); + private final Supplier<@NotNull List> faceProducer; + + private CachedFace(Supplier<@NotNull List> faceProducer) { + this.faceProducer = faceProducer; + } + + @NotNull List get() { + //noinspection ConstantConditions + return reference.updateAndGet(value -> { + Pos entityPosition = entity.getPosition(); + if (value == null || !value.lastPosition.samePoint(entityPosition)) { + return new PositionedPoints(entityPosition, faceProducer.get()); + } + return value; + }).points; + } + + } + + private static class PositionedPoints { + + private final @NotNull Pos lastPosition; + private final @NotNull List points; + + private PositionedPoints(@NotNull Pos lastPosition, @NotNull List points) { + this.lastPosition = lastPosition; + this.points = points; + } + + } + }