--- ../src-base/minecraft/net/minecraft/world/chunk/NibbleArray.java
+++ ../src-work/minecraft/net/minecraft/world/chunk/NibbleArray.java
@@ -1,47 +1,215 @@
 package net.minecraft.world.chunk;
 
+import java.util.Arrays; // Spigot
+
 public class NibbleArray
 {
-    public final byte[] data;
+    public byte[] data; // Spigot - remove final // Cauldron - make public
     private final int depthBits;
     private final int depthBitsPlusFour;
     private static final String __OBFID = "CL_00000371";
 
-    public NibbleArray(int p_i1992_1_, int p_i1992_2_)
+    // Spigot start
+    private byte trivialValue;
+    private byte trivialByte;
+    private int length;
+    private static final int LEN2K = 2048; // Universal length used right now - optimize around this
+    private static final byte[][] TrivLen2k;
+
+    static
     {
-        this.data = new byte[p_i1992_1_ >> 1];
-        this.depthBits = p_i1992_2_;
-        this.depthBitsPlusFour = p_i1992_2_ + 4;
+        TrivLen2k = new byte[16][];
+
+        for (int i = 0; i < 16; i++)
+        {
+            TrivLen2k[i] = new byte[LEN2K];
+            Arrays.fill(TrivLen2k[i], (byte)(i | (i << 4)));
+        }
     }
 
-    public NibbleArray(byte[] p_i1993_1_, int p_i1993_2_)
+    // Try to convert array to trivial array
+    public void detectAndProcessTrivialArray()
     {
-        this.data = p_i1993_1_;
-        this.depthBits = p_i1993_2_;
-        this.depthBitsPlusFour = p_i1993_2_ + 4;
+        trivialValue = (byte)(data[0] & 0xF);
+        trivialByte = (byte)(trivialValue | (trivialValue << 4));
+
+        for (int i = 0; i < data.length; i++)
+        {
+            if (data[i] != trivialByte)
+            {
+                return;
+            }
+        }
+
+        // All values matches, so array is trivial
+        this.length = data.length;
+        this.data = null;
     }
 
-    public int get(int p_76582_1_, int p_76582_2_, int p_76582_3_)
+    // Force array to non-trivial state
+    public void forceToNonTrivialArray()
     {
-        int l = p_76582_2_ << this.depthBitsPlusFour | p_76582_3_ << this.depthBits | p_76582_1_;
+        if (this.data == null)
+        {
+            this.data = new byte[this.length];
+
+            if (this.trivialByte != 0)
+            {
+                Arrays.fill(this.data, this.trivialByte);
+            }
+        }
+    }
+
+    // Test if array is in trivial state
+    public boolean isTrivialArray()
+    {
+        return (this.data == null);
+    }
+
+    // Get value of all elements (only valid if array is in trivial state)
+    public int getTrivialArrayValue()
+    {
+        return this.trivialValue;
+    }
+
+    // Get logical length of byte array for nibble data (whether trivial or non-trivial)
+    public int getByteLength()
+    {
+        if (this.data == null)
+        {
+            return this.length;
+        }
+        else
+        {
+            return this.data.length;
+        }
+    }
+
+    // Return byte encoding of array (whether trivial or non-trivial) - returns read-only array if trivial (do not modify!)
+    public byte[] getValueArray()
+    {
+        if (this.data != null)
+        {
+            return this.data;
+        }
+        else
+        {
+            byte[] rslt;
+
+            if (this.length == LEN2K)    // All current uses are 2k long, but be safe
+            {
+                rslt = TrivLen2k[this.trivialValue];
+            }
+            else
+            {
+                rslt = new byte[this.length];
+
+                if (this.trivialByte != 0)
+                {
+                    Arrays.fill(rslt, this.trivialByte);
+                }
+            }
+
+            return rslt;
+        }
+    }
+
+    // Copy byte representation of array to given offset in given byte array
+    public int copyToByteArray(byte[] dest, int off)
+    {
+        if (this.data == null)
+        {
+            Arrays.fill(dest, off, off + this.length, this.trivialByte);
+            return off + this.length;
+        }
+        else
+        {
+            System.arraycopy(this.data, 0, dest, off, this.data.length);
+            return off + this.data.length;
+        }
+    }
+
+    // Resize array to given byte length
+    public void resizeArray(int len)
+    {
+        if (this.data == null)
+        {
+            this.length = len;
+        }
+        else if (this.data.length != len)
+        {
+            byte[] newa = new byte[len];
+            System.arraycopy(this.data, 0, newa, 0, ((this.data.length > len) ? len : this.data.length));
+            this.data = newa;
+        }
+    }
+    // Spigot end
+
+    public NibbleArray(int par1, int par2)
+    {
+        // Spigot start
+        //this.a = new byte[i >> 1];
+        this.data = null; // Start off as trivial value (all same zero value)
+        this.length = par1 >> 1;
+        this.trivialByte = this.trivialValue = 0;
+        // Spigot end
+        this.depthBits = par2;
+        this.depthBitsPlusFour = par2 + 4;
+    }
+
+    public NibbleArray(byte[] par1ArrayOfByte, int par2)
+    {
+        this.data = par1ArrayOfByte;
+        this.depthBits = par2;
+        this.depthBitsPlusFour = par2 + 4;
+        detectAndProcessTrivialArray(); // Spigot
+    }
+
+    public int get(int par1, int par2, int par3)
+    {
+        if (this.data == null)
+        {
+            return this.trivialValue;    // Spigot
+        }
+
+        int l = par2 << this.depthBitsPlusFour | par3 << this.depthBits | par1;
         int i1 = l >> 1;
         int j1 = l & 1;
         return j1 == 0 ? this.data[i1] & 15 : this.data[i1] >> 4 & 15;
     }
 
-    public void set(int p_76581_1_, int p_76581_2_, int p_76581_3_, int p_76581_4_)
+    public void set(int par1, int par2, int par3, int par4)
     {
-        int i1 = p_76581_2_ << this.depthBitsPlusFour | p_76581_3_ << this.depthBits | p_76581_1_;
+        // Spigot start
+        if (this.data == null)
+        {
+            if (par4 != this.trivialValue)   // Not same as trivial value, array no longer trivial
+            {
+                this.data = new byte[this.length];
+
+                if (this.trivialByte != 0)
+                {
+                    Arrays.fill(this.data, this.trivialByte);
+                }
+            }
+            else
+            {
+                return;
+            }
+        }
+
+        // Spigot end
+        int i1 = par2 << this.depthBitsPlusFour | par3 << this.depthBits | par1;
         int j1 = i1 >> 1;
         int k1 = i1 & 1;
 
         if (k1 == 0)
         {
-            this.data[j1] = (byte)(this.data[j1] & 240 | p_76581_4_ & 15);
+            this.data[j1] = (byte)(this.data[j1] & 240 | par4 & 15);
         }
         else
         {
-            this.data[j1] = (byte)(this.data[j1] & 15 | (p_76581_4_ & 15) << 4);
+            this.data[j1] = (byte)(this.data[j1] & 15 | (par4 & 15) << 4);
         }
     }
 }
