--- a/net/minecraft/core/Direction.java
+++ b/net/minecraft/core/Direction.java
@@ -29,7 +_,7 @@
 import org.joml.Vector3f;
 import org.joml.Vector3fc;
 
-public enum Direction implements StringRepresentable {
+public enum Direction implements StringRepresentable, ca.spottedleaf.moonrise.patches.collisions.util.CollisionDirection { // Paper - optimise collisions
     DOWN(0, 1, -1, "down", Direction.AxisDirection.NEGATIVE, Direction.Axis.Y, new Vec3i(0, -1, 0)),
     UP(1, 0, -1, "up", Direction.AxisDirection.POSITIVE, Direction.Axis.Y, new Vec3i(0, 1, 0)),
     NORTH(2, 3, 2, "north", Direction.AxisDirection.NEGATIVE, Direction.Axis.Z, new Vec3i(0, 0, -1)),
@@ -65,6 +_,52 @@
         .sorted(Comparator.comparingInt(direction -> direction.data2d))
         .toArray(Direction[]::new);
 
+    // Paper start - Perf: Inline shift direction fields
+    private final int adjX;
+    private final int adjY;
+    private final int adjZ;
+    // Paper end - Perf: Inline shift direction fields
+    // Paper start - optimise collisions
+    private static final int RANDOM_OFFSET = 2017601568;
+    private Direction opposite;
+    private Quaternionf rotation;
+    private int id;
+    private int stepX;
+    private int stepY;
+    private int stepZ;
+
+    private Quaternionf getRotationUncached() {
+        switch ((Direction)(Object)this) {
+            case DOWN: {
+                return new Quaternionf().rotationX(3.1415927F);
+            }
+            case UP: {
+                return new Quaternionf();
+            }
+            case NORTH: {
+                return new Quaternionf().rotationXYZ(1.5707964F, 0.0F, 3.1415927F);
+            }
+            case SOUTH: {
+                return new Quaternionf().rotationX(1.5707964F);
+            }
+            case WEST: {
+                return new Quaternionf().rotationXYZ(1.5707964F, 0.0F, 1.5707964F);
+            }
+            case EAST: {
+                return new Quaternionf().rotationXYZ(1.5707964F, 0.0F, -1.5707964F);
+            }
+            default: {
+                throw new IllegalStateException();
+            }
+        }
+    }
+
+    @Override
+    public final int moonrise$uniqueId() {
+        return this.id;
+    }
+    // Paper end - optimise collisions
+
     private Direction(
         final int data3d,
         final int oppositeIndex,
@@ -83,6 +_,11 @@
         this.normal = normal;
         this.normalVec3 = Vec3.atLowerCornerOf(normal);
         this.normalVec3f = new Vector3f(normal.getX(), normal.getY(), normal.getZ());
+        // Paper start - Perf: Inline shift direction fields
+        this.adjX = normal.getX();
+        this.adjY = normal.getY();
+        this.adjZ = normal.getZ();
+        // Paper end - Perf: Inline shift direction fields
     }
 
     public static Direction[] orderedByNearest(Entity entity) {
@@ -144,14 +_,13 @@
     }
 
     public Quaternionf getRotation() {
-        return switch (this) {
-            case DOWN -> new Quaternionf().rotationX((float) Math.PI);
-            case UP -> new Quaternionf();
-            case NORTH -> new Quaternionf().rotationXYZ((float) (Math.PI / 2), 0.0F, (float) Math.PI);
-            case SOUTH -> new Quaternionf().rotationX((float) (Math.PI / 2));
-            case WEST -> new Quaternionf().rotationXYZ((float) (Math.PI / 2), 0.0F, (float) (Math.PI / 2));
-            case EAST -> new Quaternionf().rotationXYZ((float) (Math.PI / 2), 0.0F, (float) (-Math.PI / 2));
-        };
+        // Paper start - optimise collisions
+        try {
+            return (Quaternionf)this.rotation.clone();
+        } catch (final CloneNotSupportedException ex) {
+            throw new InternalError(ex);
+        }
+        // Paper end - optimise collisions
     }
 
     public int get3DDataValue() {
@@ -175,7 +_,7 @@
     }
 
     public Direction getOpposite() {
-        return from3DDataValue(this.oppositeIndex);
+        return this.opposite; // Paper - optimise collisions
     }
 
     public Direction getClockWise(Direction.Axis axis) {
@@ -255,15 +_,15 @@
     }
 
     public int getStepX() {
-        return this.normal.getX();
+        return this.adjX; // Paper - Perf: Inline shift direction fields
     }
 
     public int getStepY() {
-        return this.normal.getY();
+        return this.adjY; // Paper - Perf: Inline shift direction fields
     }
 
     public int getStepZ() {
-        return this.normal.getZ();
+        return this.adjZ; // Paper - Perf: Inline shift direction fields
     }
 
     public Vector3f step() {
@@ -622,4 +_,17 @@
             return this.faces.length;
         }
     }
+
+    // Paper start - optimise collisions
+    static {
+        for (final Direction direction : VALUES) {
+            ((Direction)(Object)direction).opposite = from3DDataValue(((Direction)(Object)direction).oppositeIndex);
+            ((Direction)(Object)direction).rotation = ((Direction)(Object)direction).getRotationUncached();
+            ((Direction)(Object)direction).id = it.unimi.dsi.fastutil.HashCommon.murmurHash3(it.unimi.dsi.fastutil.HashCommon.murmurHash3(direction.ordinal() + RANDOM_OFFSET) + RANDOM_OFFSET);
+            ((Direction)(Object)direction).stepX = ((Direction)(Object)direction).normal.getX();
+            ((Direction)(Object)direction).stepY = ((Direction)(Object)direction).normal.getY();
+            ((Direction)(Object)direction).stepZ = ((Direction)(Object)direction).normal.getZ();
+        }
+    }
+    // Paper end - optimise collisions
 }
