Browse Source

Move our Externalizeable to PrimitveExChunkletStore
This will let us deserialize Primitive normally.

In addition, we now enforce all chunklets being of type PrimitiveEx, as any non-Ex are repalced with a new Ex on load.

NuclearW 13 years ago
parent
commit
da6b461408

+ 11 - 2
src/main/java/com/gmail/nossr50/util/blockmeta/ChunkletStore.java

@@ -1,9 +1,11 @@
 package com.gmail.nossr50.util.blockmeta;
 
-import java.io.Externalizable;
 import java.io.Serializable;
 
-public interface ChunkletStore extends Serializable, Externalizable {
+/**
+ * A ChunkletStore should be responsible for a 16x16x64 area of data
+ */
+public interface ChunkletStore extends Serializable {
     /**
      * Checks the value at the given coordinates
      *
@@ -36,4 +38,11 @@ public interface ChunkletStore extends Serializable, Externalizable {
      * @return true if all values in the chunklet are false, false if otherwise
      */
     public boolean isEmpty();
+
+    /**
+     * Set all values in this ChunkletStore to the values from another provided ChunkletStore
+     *
+     * @param otherStore Another ChunkletStore that this one should copy all data from
+     */
+    public void copyFrom(ChunkletStore otherStore);
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/util/blockmeta/ChunkletStoreFactory.java

@@ -3,6 +3,6 @@ package com.gmail.nossr50.util.blockmeta;
 public class ChunkletStoreFactory {
     protected static ChunkletStore getChunkletStore() {
         // TODO: Add in loading from config what type of store we want.
-        return new PrimitiveChunkletStore();
+        return new PrimitiveExChunkletStore();
     }
 }

+ 9 - 0
src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkletManager.java

@@ -338,6 +338,15 @@ public class HashChunkletManager implements ChunkletManager {
             }
         }
 
+        // TODO: Make this less messy, as it is, it's kinda... depressing to do it like this.
+        // Might also make a mess when we move to stacks, but at that point I think I will write a new Manager...
+        // IMPORTANT! If ChunkletStoreFactory is going to be returning something other than PrimitiveEx we need to remove this, as it will be breaking time for old maps
+        if(!(storeIn instanceof PrimitiveExChunkletStore)) {
+            ChunkletStore tempStore = ChunkletStoreFactory.getChunkletStore();
+            tempStore.copyFrom(storeIn);
+            storeIn = tempStore;
+        }
+
         return storeIn;
     }
 }

+ 3 - 123
src/main/java/com/gmail/nossr50/util/blockmeta/PrimitiveChunkletStore.java

@@ -1,14 +1,10 @@
 package com.gmail.nossr50.util.blockmeta;
 
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-
 public class PrimitiveChunkletStore implements ChunkletStore {
     private static final long serialVersionUID = -3453078050608607478L;
 
     /** X, Z, Y */
-    private boolean[][][] store = new boolean[16][16][64];
+    protected boolean[][][] store = new boolean[16][16][64];
 
     @Override
     public boolean isTrue(int x, int y, int z) {
@@ -38,129 +34,13 @@ public class PrimitiveChunkletStore implements ChunkletStore {
     }
 
     @Override
-    public void writeExternal(ObjectOutput out) throws IOException {
-        byte[] buffer = new byte[2304]; // 2304 is 16*16*9
-        int bufferIndex = 0;
-
+    public void copyFrom(ChunkletStore otherStore) {
         for(int x = 0; x < 16; x++) {
             for(int z = 0; z < 16; z++) {
                 for(int y = 0; y < 64; y++) {
-                    if(store[x][z][y]) {
-                        byte[] temp = constructColumn(x, z);
-
-                        for(int i = 0; i < 9; i++) {
-                            buffer[bufferIndex] = temp[i];
-                            bufferIndex++;
-                        }
-
-                        break;
-                    }
-                }
-            }
-        }
-
-        out.write(buffer, 0, bufferIndex);
-        out.flush();
-    }
-
-    // For this we assume that store has been initialized to be all false by now
-    @Override
-    public void readExternal(ObjectInput in) throws IOException {
-        byte[] temp = new byte[9];
-
-        // Could probably reorganize this loop to print nasty things if it does not equal 9 or -1
-        while(in.read(temp, 0, 9) == 9) {
-            int x = addressByteX(temp[0]);
-            int z = addressByteZ(temp[0]);
-            boolean[] yColumn = new boolean[64];
-
-            for(int i = 0; i < 8; i++) {
-                for(int j = 0; j < 8; j++) {
-                    yColumn[j + (i * 8)] = (temp[i + 1] & (1 << j)) != 0;
-                }
-            }
-
-            store[x][z] = yColumn;
-        }
-    }
-
-    /*
-     * The column: An array of 9 bytes which represent all y values for a given (x,z) Chunklet-coordinate
-     *
-     * The first byte is an address byte, this provides the x and z values.
-     * The next 8 bytes are all y values from 0 to 63, with each byte containing 8 bits of true/false data
-     *
-     * Each of these 8 bytes address to a y value from right to left
-     *
-     * Examples:
-     * 00000001 represents that the lowest y value in this byte is true, all others are off
-     * 10000000 represents that the highest y value in this byte is true, all others are off
-     * 10000001 represents that the lowest and highest y values in this byte are true, all others are off
-     *
-     * Full columns:
-     * See comment on Address byte for information on how to use that byte
-     *
-     * Example:
-     * ADDRESS_BYTE 10000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000
-     *  - x, z from ADDRESS_BYTE
-     *  - The next byte contains data from 0 to 7
-     *    - 1 is set in the highest bit position, this is 7 in y coordinate
-     *  - The next byte contains data from 8 to 15
-     *    - 1 is set in the lowest bit position, this is 8 in the y coordinate
-     *  Therefore, for this column: There are true values at (x, 7, z) and (x, 8, z)
-     */
-    private byte[] constructColumn(int x, int z) {
-        byte[] column = new byte[9];
-        int index = 1;
-
-        column[0] = makeAddressByte(x, z);
-
-        for (int i = 0; i < 8; i++){
-            byte yCompressed = 0x0;
-            int subColumnIndex = 8 * i;
-            int subColumnEnd = subColumnIndex + 8;
-
-            for(int y = subColumnIndex; y < subColumnEnd; y++) {
-                if(store[x][z][y]) {
-                    yCompressed |= 1 << (y % 8);
+                    store[x][z][y] = otherStore.isTrue(x, y, z);
                 }
             }
-
-            column[index] = yCompressed;
-            index++;
         }
-
-        return column;
-    }
-
-    /*
-     * The address byte: A single byte which contains x and z values which correspond to the x and z Chunklet-coordinates
-     *
-     * In Chunklet-coordinates, the only valid values are 0-15, so we can fit both into a single byte.
-     *
-     * The top 4 bits of the address byte are for the x value
-     * The bottom 4 bits of the address byte are for the z value
-     *
-     * Examples:
-     * An address byte with a value 00000001 would be split like so:
-     *  - x = 0000 = 0
-     *  - z = 0001 = 1
-     *  => Chunklet coordinates (0, 1)
-     *
-     * 01011111
-     *  - x = 0101 = 5
-     *  - z = 1111 = 15
-     *  => Chunklet coordinates (5, 15)
-     */
-    private static byte makeAddressByte(int x, int z) {
-        return (byte) ((x << 4) + z);
-    }
-
-    private static int addressByteX(byte address) {
-        return (address & 0xF0) >>> 4;
-    }
-
-    private static int addressByteZ(byte address) {
-        return address & 0x0F;
     }
 }

+ 178 - 0
src/main/java/com/gmail/nossr50/util/blockmeta/PrimitiveExChunkletStore.java

@@ -0,0 +1,178 @@
+package com.gmail.nossr50.util.blockmeta;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+public class PrimitiveExChunkletStore implements ChunkletStore, Externalizable {
+	private static final long serialVersionUID = 8603603827094383873L;
+
+    /** X, Z, Y */
+    private boolean[][][] store = new boolean[16][16][64];
+
+    @Override
+    public boolean isTrue(int x, int y, int z) {
+        return store[x][z][y];
+    }
+
+    @Override
+    public void setTrue(int x, int y, int z) {
+        store[x][z][y] = true;
+    }
+
+    @Override
+    public void setFalse(int x, int y, int z) {
+        store[x][z][y] = false;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        for(int x = 0; x < 16; x++) {
+            for(int z = 0; z < 16; z++) {
+                for(int y = 0; y < 64; y++) {
+                    if(store[x][z][y]) return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void copyFrom(ChunkletStore otherStore) {
+        for(int x = 0; x < 16; x++) {
+            for(int z = 0; z < 16; z++) {
+                for(int y = 0; y < 64; y++) {
+                    store[x][z][y] = otherStore.isTrue(x, y, z);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        byte[] buffer = new byte[2304]; // 2304 is 16*16*9
+        int bufferIndex = 0;
+
+        for(int x = 0; x < 16; x++) {
+            for(int z = 0; z < 16; z++) {
+                for(int y = 0; y < 64; y++) {
+                    if(store[x][z][y]) {
+                        byte[] temp = constructColumn(x, z);
+
+                        for(int i = 0; i < 9; i++) {
+                            buffer[bufferIndex] = temp[i];
+                            bufferIndex++;
+                        }
+
+                        break;
+                    }
+                }
+            }
+        }
+
+        out.write(buffer, 0, bufferIndex);
+        out.flush();
+    }
+
+    // For this we assume that store has been initialized to be all false by now
+    @Override
+    public void readExternal(ObjectInput in) throws IOException {
+        byte[] temp = new byte[9];
+
+        // Could probably reorganize this loop to print nasty things if it does not equal 9 or -1
+        while(in.read(temp, 0, 9) == 9) {
+            int x = addressByteX(temp[0]);
+            int z = addressByteZ(temp[0]);
+            boolean[] yColumn = new boolean[64];
+
+            for(int i = 0; i < 8; i++) {
+                for(int j = 0; j < 8; j++) {
+                    yColumn[j + (i * 8)] = (temp[i + 1] & (1 << j)) != 0;
+                }
+            }
+
+            store[x][z] = yColumn;
+        }
+    }
+
+    /*
+     * The column: An array of 9 bytes which represent all y values for a given (x,z) Chunklet-coordinate
+     *
+     * The first byte is an address byte, this provides the x and z values.
+     * The next 8 bytes are all y values from 0 to 63, with each byte containing 8 bits of true/false data
+     *
+     * Each of these 8 bytes address to a y value from right to left
+     *
+     * Examples:
+     * 00000001 represents that the lowest y value in this byte is true, all others are off
+     * 10000000 represents that the highest y value in this byte is true, all others are off
+     * 10000001 represents that the lowest and highest y values in this byte are true, all others are off
+     *
+     * Full columns:
+     * See comment on Address byte for information on how to use that byte
+     *
+     * Example:
+     * ADDRESS_BYTE 10000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000
+     *  - x, z from ADDRESS_BYTE
+     *  - The next byte contains data from 0 to 7
+     *    - 1 is set in the highest bit position, this is 7 in y coordinate
+     *  - The next byte contains data from 8 to 15
+     *    - 1 is set in the lowest bit position, this is 8 in the y coordinate
+     *  Therefore, for this column: There are true values at (x, 7, z) and (x, 8, z)
+     */
+    private byte[] constructColumn(int x, int z) {
+        byte[] column = new byte[9];
+        int index = 1;
+
+        column[0] = makeAddressByte(x, z);
+
+        for (int i = 0; i < 8; i++){
+            byte yCompressed = 0x0;
+            int subColumnIndex = 8 * i;
+            int subColumnEnd = subColumnIndex + 8;
+
+            for(int y = subColumnIndex; y < subColumnEnd; y++) {
+                if(store[x][z][y]) {
+                    yCompressed |= 1 << (y % 8);
+                }
+            }
+
+            column[index] = yCompressed;
+            index++;
+        }
+
+        return column;
+    }
+
+    /*
+     * The address byte: A single byte which contains x and z values which correspond to the x and z Chunklet-coordinates
+     *
+     * In Chunklet-coordinates, the only valid values are 0-15, so we can fit both into a single byte.
+     *
+     * The top 4 bits of the address byte are for the x value
+     * The bottom 4 bits of the address byte are for the z value
+     *
+     * Examples:
+     * An address byte with a value 00000001 would be split like so:
+     *  - x = 0000 = 0
+     *  - z = 0001 = 1
+     *  => Chunklet coordinates (0, 1)
+     *
+     * 01011111
+     *  - x = 0101 = 5
+     *  - z = 1111 = 15
+     *  => Chunklet coordinates (5, 15)
+     */
+    private static byte makeAddressByte(int x, int z) {
+        return (byte) ((x << 4) + z);
+    }
+
+    private static int addressByteX(byte address) {
+        return (address & 0xF0) >>> 4;
+    }
+
+    private static int addressByteZ(byte address) {
+        return address & 0x0F;
+    }
+}