From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 14 Aug 2018 21:42:10 -0700
Subject: [PATCH] Allow Blocks to be accessed via a long key

The key can be retrieved via methods Location#toBlockKey() and
Block#getBlockKey()

World provides lookup for blocks by long key via method World#getBlockAtKey(long)

The formatting for the key is as follows:

10 bit y|27 bit z|27 bit x

The y value is considered unsigned while z and x are considered two's complement

Y range: [0, 1023]
X, Z range: [-67 108 864, 67 108 863]

diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java
index 36ed248f0716f2cc465c08ab851b7d83d4c7c0a7..5c5e05673e0912f4dbd6c728f4c3b7fcdae8f0e8 100644
--- a/src/main/java/org/bukkit/Location.java
+++ b/src/main/java/org/bukkit/Location.java
@@ -15,7 +15,6 @@ import org.jetbrains.annotations.Nullable;
 
 // Paper start
 import java.util.Collection;
-import java.util.Collections;
 import java.util.function.Predicate;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.LivingEntity;
@@ -605,6 +604,19 @@ public class Location implements Cloneable, ConfigurationSerializable {
         blockLoc.setZ(getBlockZ());
         return blockLoc;
     }
+
+    // Paper Start
+    /**
+     * @return The block key for this location's block location.
+     * @see Block#getBlockKey(int, int, int)
+     * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail
+     */
+    @Deprecated
+    public long toBlockKey() {
+        return Block.getBlockKey(getBlockX(), getBlockY(), getBlockZ());
+    }
+    // Paper End
+
     /**
      * @return A new location where X/Y/Z are the center of the block
      */
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
index a501384906fa01ddc83476ef2dbbb8d11a03fb8c..449d6882c8f41d9e0f46436c430e071b85eb2775 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -92,6 +92,40 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
     @NotNull
     public Block getBlockAt(@NotNull Location location);
 
+    // Paper start
+    /**
+     * Gets the {@link Block} at the given block key
+     *
+     * @param key The block key. See {@link Block#getBlockKey()}
+     * @return Block at the key
+     * @see Block#getBlockKey(int, int, int)
+     * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail
+     */
+    @NotNull
+    @Deprecated
+    public default Block getBlockAtKey(long key) {
+        int x = Block.getBlockKeyX(key);
+        int y = Block.getBlockKeyY(key);
+        int z = Block.getBlockKeyZ(key);
+        return getBlockAt(x, y, z);
+    }
+
+    /**
+     * Gets the {@link Location} at the given block key
+     *
+     * @param key The block key. See {@link Location#toBlockKey()}
+     * @return Location at the key
+     * @see Block#getBlockKey(int, int, int)
+     */
+    @NotNull
+    public default Location getLocationAtKey(long key) {
+        int x = Block.getBlockKeyX(key);
+        int y = Block.getBlockKeyY(key);
+        int z = Block.getBlockKeyZ(key);
+        return new Location(this, x, y, z);
+    }
+    // Paper end
+
     /**
      * Gets the highest non-empty (impassable) coordinate at the given
      * coordinates.
diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java
index d29bdc125dba0128d93d57e8d9393b970e6c00a9..b101f5264bdde8bd14913d5161c1047020830f8d 100644
--- a/src/main/java/org/bukkit/block/Block.java
+++ b/src/main/java/org/bukkit/block/Block.java
@@ -155,6 +155,82 @@ public interface Block extends Metadatable {
      */
     int getZ();
 
+    // Paper Start
+    /**
+     * Returns this block's coordinates packed into a long value.
+     * Computed via: {@code Block.getBlockKey(this.getX(), this.getY(), this.getZ())}
+     * @see Block#getBlockKey(int, int, int)
+     * @return This block's x, y, and z coordinates packed into a long value
+     * @deprecated see {@link #getBlockKey(int, int, int)}
+     */
+    @Deprecated
+    public default long getBlockKey() {
+        return Block.getBlockKey(this.getX(), this.getY(), this.getZ());
+    }
+
+    /**
+     * Returns the specified block coordinates packed into a long value
+     * <p>
+     * The return value can be computed as follows:
+     * <br>
+     * {@code long value = ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54);}
+     * </p>
+     *
+     * <p>
+     * And may be unpacked as follows:
+     * <br>
+     * {@code int x = (int) ((packed << 37) >> 37);}
+     * <br>
+     * {@code int y = (int) (packed >> 54);}
+     * <br>
+     * {@code int z = (int) ((packed << 10) >> 37);}
+     * </p>
+     *
+     * @return This block's x, y, and z coordinates packed into a long value
+     * @deprecated only encodes y block ranges from -512 to 511 and represents an already changed implementation detail
+     */
+    @Deprecated
+    public static long getBlockKey(int x, int y, int z) {
+        return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54);
+    }
+
+    /**
+     * Returns the x component from the packed value.
+     * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)}
+     * @see Block#getBlockKey(int, int, int)
+     * @return The x component from the packed value.
+     * @deprecated see {@link #getBlockKey(int, int, int)}
+     */
+    @Deprecated
+    public static int getBlockKeyX(long packed) {
+        return (int) ((packed << 37) >> 37);
+    }
+
+    /**
+     * Returns the y component from the packed value.
+     * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)}
+     * @see Block#getBlockKey(int, int, int)
+     * @return The y component from the packed value.
+     * @deprecated see {@link #getBlockKey(int, int, int)}
+     */
+    @Deprecated
+    public static int getBlockKeyY(long packed) {
+        return (int) (packed >> 54);
+    }
+
+    /**
+     * Returns the z component from the packed value.
+     * @param packed The packed value, as computed by {@link Block#getBlockKey(int, int, int)}
+     * @see Block#getBlockKey(int, int, int)
+     * @return The z component from the packed value.
+     * @deprecated see {@link #getBlockKey(int, int, int)}
+     */
+    @Deprecated
+    public static int getBlockKeyZ(long packed) {
+        return (int) ((packed << 10) >> 37);
+    }
+    // Paper End
+
     /**
      * Gets the Location of the block
      *