Skip to content
This repository
Browse code

+ implemented serialization handlers using ByteBuffers for every tera…

… array

+ implemented benchmarks for different ways of serializing tera arrays
+ added Chunks.proto describing simple messages for chunks and tera arrays
- removed stream based serialization handlers due to massive performance problems
  • Loading branch information...
commit 0a0f69ca07cfc9b73d1a6d946e705d9370137a0f 1 parent ef90f9e
mbrotz authored

Showing 22 changed files with 704 additions and 241 deletions. Show diff stats Hide diff stats

  1. 0  protobuf/compiler/protoc.exe
  2. 48  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayDeserializeFromBuffer.java
  3. 40  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerialization.java
  4. 53  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeObject.java
  5. 48  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToBuffer.java
  6. 58  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaByteArray.java
  7. 62  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaChannel.java
  8. 14  src/dev/java/org/terasology/benchmark/chunks/arrays/TeraArraysBenchmark.java
  9. 18  src/main/java/org/terasology/config/AdvancedConfig.java
  10. 20  src/main/java/org/terasology/io/SerializationHandler.java
  11. 106  src/main/java/org/terasology/world/chunks/blockdata/TeraArray.java
  12. 19  src/main/java/org/terasology/world/chunks/blockdata/TeraArrayFactory.java
  13. 23  src/main/java/org/terasology/world/chunks/blockdata/TeraArraySerializationHandler.java
  14. 56  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArray16Bit.java
  15. 18  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArray4Bit.java
  16. 18  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArray8Bit.java
  17. 43  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArrayByte.java
  18. 126  src/main/java/org/terasology/world/chunks/blockdata/TeraSparseArray16Bit.java
  19. 17  src/main/java/org/terasology/world/chunks/blockdata/TeraSparseArray4Bit.java
  20. 19  src/main/java/org/terasology/world/chunks/blockdata/TeraSparseArray8Bit.java
  21. 107  src/main/java/org/terasology/world/chunks/blockdata/TeraSparseArrayByte.java
  22. 32  src/main/protobuf/Chunks.proto
0  protobuf/compiler/protoc.exe 100644 → 100755
File mode changed
48  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayDeserializeFromBuffer.java
... ...
@@ -0,0 +1,48 @@
  1
+package org.terasology.benchmark.chunks.arrays;
  2
+
  3
+import java.nio.ByteBuffer;
  4
+
  5
+import org.terasology.benchmark.BenchmarkResult;
  6
+import org.terasology.world.chunks.blockdata.TeraArray;
  7
+import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler;
  8
+
  9
+public class BenchmarkTeraArrayDeserializeFromBuffer extends BenchmarkTeraArraySerialization {
  10
+
  11
+    protected ByteBuffer buffer;
  12
+    
  13
+    @SuppressWarnings("rawtypes")
  14
+    public BenchmarkTeraArrayDeserializeFromBuffer(SerializationHandler handler, TeraArray array) {
  15
+        super(handler, array);
  16
+    }
  17
+
  18
+    @Override
  19
+    public String getTitle() {
  20
+        return array.getClass().getSimpleName() + " deserialization from buffer";
  21
+    }
  22
+
  23
+    @SuppressWarnings("unchecked")
  24
+    @Override
  25
+    public void setup() {
  26
+        buffer = ByteBuffer.allocate(BUFFER_SIZE);
  27
+        handler.serialize(array, buffer);
  28
+        buffer.rewind();
  29
+    }
  30
+
  31
+    @Override
  32
+    public void prerun(int index) {}
  33
+
  34
+    @Override
  35
+    public int run(int index, int repetitions, BenchmarkResult result) {
  36
+        for (int i = 0; i < repetitions; i++) {
  37
+            handler.deserialize(buffer);
  38
+            buffer.rewind();
  39
+        }
  40
+        return 0;
  41
+    }
  42
+
  43
+    @Override
  44
+    public void postrun(int index, BenchmarkResult result) {}
  45
+
  46
+    @Override
  47
+    public void finish(boolean aborted) {}
  48
+}
40  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerialization.java
... ...
@@ -0,0 +1,40 @@
  1
+package org.terasology.benchmark.chunks.arrays;
  2
+
  3
+import org.terasology.benchmark.BasicBenchmarkResult;
  4
+import org.terasology.benchmark.Benchmark;
  5
+import org.terasology.benchmark.BenchmarkResult;
  6
+import org.terasology.world.chunks.blockdata.TeraArray;
  7
+
  8
+import com.google.common.base.Preconditions;
  9
+
  10
+@SuppressWarnings("rawtypes")
  11
+public abstract class BenchmarkTeraArraySerialization extends Benchmark {
  12
+
  13
+    public static final int BUFFER_SIZE = 1024 * 1024;
  14
+    
  15
+    public final TeraArray.SerializationHandler handler;
  16
+    public final TeraArray array;
  17
+    
  18
+    @SuppressWarnings("unchecked")
  19
+    public BenchmarkTeraArraySerialization(TeraArray.SerializationHandler handler, TeraArray array) {
  20
+        this.handler = Preconditions.checkNotNull(handler);
  21
+        this.array = Preconditions.checkNotNull(array);
  22
+        Preconditions.checkArgument(handler.canHandle(array.getClass()), "The supplied serialization handler is incompatible to the supplied array");
  23
+    }
  24
+
  25
+    @Override
  26
+    public int getWarmupRepetitions() {
  27
+        return 10000;
  28
+    }
  29
+
  30
+    @Override
  31
+    public int[] getRepetitions() {
  32
+        return new int[] {1000, 5000, 10000};
  33
+    }
  34
+
  35
+    @Override
  36
+    public BenchmarkResult createResult() {
  37
+        return new BasicBenchmarkResult(this);
  38
+    }
  39
+
  40
+}
53  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeObject.java
... ...
@@ -0,0 +1,53 @@
  1
+package org.terasology.benchmark.chunks.arrays;
  2
+
  3
+import java.io.ByteArrayOutputStream;
  4
+import java.io.IOException;
  5
+import java.io.ObjectOutputStream;
  6
+
  7
+import org.terasology.benchmark.BenchmarkResult;
  8
+import org.terasology.world.chunks.blockdata.TeraArray;
  9
+import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler;
  10
+
  11
+public class BenchmarkTeraArraySerializeObject extends BenchmarkTeraArraySerialization {
  12
+
  13
+    protected ByteArrayOutputStream out;
  14
+
  15
+    @SuppressWarnings("rawtypes")
  16
+    public BenchmarkTeraArraySerializeObject(SerializationHandler handler, TeraArray array) {
  17
+        super(handler, array);
  18
+    }
  19
+
  20
+    @Override
  21
+    public String getTitle() {
  22
+        return array.getClass().getSimpleName() + " builtin object serialization directly into ByteArrayOutputStream";
  23
+    }
  24
+
  25
+    @Override
  26
+    public void setup() {
  27
+        out = new ByteArrayOutputStream(BUFFER_SIZE);
  28
+    }
  29
+
  30
+    @Override
  31
+    public void prerun(int index) {}
  32
+
  33
+    @Override
  34
+    public int run(int index, int repetitions, BenchmarkResult result) {
  35
+        try {
  36
+            int bogus = 0;
  37
+            for (int i = 0; i < repetitions; i++) {
  38
+                (new ObjectOutputStream(out)).writeObject(array);
  39
+                bogus += out.size();
  40
+                out.reset();
  41
+            }
  42
+            return bogus;
  43
+        } catch (IOException e) {
  44
+            throw new RuntimeException(e);
  45
+        }
  46
+    }
  47
+
  48
+    @Override
  49
+    public void postrun(int index, BenchmarkResult result) {}
  50
+
  51
+    @Override
  52
+    public void finish(boolean aborted) {}
  53
+}
48  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToBuffer.java
... ...
@@ -0,0 +1,48 @@
  1
+package org.terasology.benchmark.chunks.arrays;
  2
+
  3
+import java.nio.ByteBuffer;
  4
+
  5
+import org.terasology.benchmark.BenchmarkResult;
  6
+import org.terasology.world.chunks.blockdata.TeraArray;
  7
+import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler;
  8
+
  9
+@SuppressWarnings("rawtypes")
  10
+public class BenchmarkTeraArraySerializeToBuffer extends BenchmarkTeraArraySerialization {
  11
+
  12
+    protected ByteBuffer buffer;
  13
+
  14
+    public BenchmarkTeraArraySerializeToBuffer(SerializationHandler handler, TeraArray array) {
  15
+        super(handler, array);
  16
+    }
  17
+
  18
+    @Override
  19
+    public String getTitle() {
  20
+        return array.getClass().getSimpleName() + " serialization directly into ByteBuffer";
  21
+    }
  22
+
  23
+    @Override
  24
+    public void setup() {
  25
+        buffer = ByteBuffer.allocate(BUFFER_SIZE);
  26
+    }
  27
+
  28
+    @Override
  29
+    public void prerun(int index) {}
  30
+
  31
+    @SuppressWarnings("unchecked")
  32
+    @Override
  33
+    public int run(int index, int repetitions, BenchmarkResult result) {
  34
+        int bogus = 0;
  35
+        for (int i = 0; i < repetitions; i++) {
  36
+            handler.serialize(array, buffer);
  37
+            bogus += buffer.position();
  38
+            buffer.rewind();
  39
+        }
  40
+        return bogus;
  41
+    }
  42
+
  43
+    @Override
  44
+    public void postrun(int index, BenchmarkResult result) {}
  45
+
  46
+    @Override
  47
+    public void finish(boolean aborted) {}
  48
+}
58  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaByteArray.java
... ...
@@ -0,0 +1,58 @@
  1
+package org.terasology.benchmark.chunks.arrays;
  2
+
  3
+import java.io.ByteArrayOutputStream;
  4
+import java.nio.ByteBuffer;
  5
+
  6
+import org.terasology.benchmark.BenchmarkResult;
  7
+import org.terasology.world.chunks.blockdata.TeraArray;
  8
+import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler;
  9
+
  10
+public class BenchmarkTeraArraySerializeToStreamViaByteArray extends BenchmarkTeraArraySerialization {
  11
+
  12
+    protected ByteBuffer buffer;
  13
+    protected ByteArrayOutputStream out;
  14
+    protected byte[] via;
  15
+
  16
+    @SuppressWarnings("rawtypes")
  17
+    public BenchmarkTeraArraySerializeToStreamViaByteArray(SerializationHandler handler, TeraArray array) {
  18
+        super(handler, array);
  19
+    }
  20
+
  21
+    @Override
  22
+    public String getTitle() {
  23
+        return array.getClass().getSimpleName() + " serialization into ByteBuffer and transfer via byte[] array into ByteArrayOutputStream";
  24
+    }
  25
+
  26
+    @Override
  27
+    public void setup() {
  28
+        buffer = ByteBuffer.allocate(BUFFER_SIZE);
  29
+        out = new ByteArrayOutputStream(BUFFER_SIZE);
  30
+        via = new byte[BUFFER_SIZE];
  31
+    }
  32
+
  33
+    @Override
  34
+    public void prerun(int index) {}
  35
+
  36
+    @SuppressWarnings("unchecked")
  37
+    @Override
  38
+    public int run(int index, int repetitions, BenchmarkResult result) {
  39
+        int bogus = 0;
  40
+        for (int i = 0; i < repetitions; i++) {
  41
+            handler.serialize(array, buffer);
  42
+            final int length = buffer.position();
  43
+            buffer.rewind();
  44
+            buffer.get(via, 0, length);
  45
+            buffer.rewind();
  46
+            out.write(via, 0, length);
  47
+            out.reset();
  48
+            bogus += length;
  49
+        }
  50
+        return bogus;
  51
+    }
  52
+
  53
+    @Override
  54
+    public void postrun(int index, BenchmarkResult result) {}
  55
+
  56
+    @Override
  57
+    public void finish(boolean aborted) {}
  58
+}
62  src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaChannel.java
... ...
@@ -0,0 +1,62 @@
  1
+package org.terasology.benchmark.chunks.arrays;
  2
+
  3
+import java.io.ByteArrayOutputStream;
  4
+import java.io.IOException;
  5
+import java.nio.ByteBuffer;
  6
+import java.nio.channels.Channels;
  7
+import java.nio.channels.WritableByteChannel;
  8
+
  9
+import org.terasology.benchmark.BenchmarkResult;
  10
+import org.terasology.world.chunks.blockdata.TeraArray;
  11
+
  12
+public class BenchmarkTeraArraySerializeToStreamViaChannel extends BenchmarkTeraArraySerialization {
  13
+
  14
+    protected ByteBuffer buffer;
  15
+    protected ByteArrayOutputStream out;
  16
+    protected WritableByteChannel channel;
  17
+    
  18
+    @SuppressWarnings("rawtypes")
  19
+    public BenchmarkTeraArraySerializeToStreamViaChannel(TeraArray.SerializationHandler handler, TeraArray array) {
  20
+        super(handler, array);
  21
+    }
  22
+
  23
+    @Override
  24
+    public String getTitle() {
  25
+        return array.getClass().getSimpleName() + " serialization into ByteBuffer and transfer via Channel into ByteArrayOutputStream";
  26
+    }
  27
+
  28
+    @Override
  29
+    public void setup() {
  30
+        buffer = ByteBuffer.allocate(BUFFER_SIZE);
  31
+        out = new ByteArrayOutputStream(BUFFER_SIZE);
  32
+        channel = Channels.newChannel(out);
  33
+    }
  34
+
  35
+    @Override
  36
+    public void prerun(int index) {}
  37
+
  38
+    @SuppressWarnings("unchecked")
  39
+    @Override
  40
+    public int run(int index, int repetitions, BenchmarkResult result) {
  41
+        try {
  42
+            int bogus = 0;
  43
+            for (int i = 0; i < repetitions; i++) {
  44
+                handler.serialize(array, buffer);
  45
+                bogus += buffer.position();
  46
+                buffer.rewind();
  47
+                channel.write(buffer);
  48
+                buffer.rewind();
  49
+                out.reset();
  50
+            }
  51
+            return bogus;
  52
+        } catch (IOException e) {
  53
+            throw new RuntimeException(e);
  54
+        }
  55
+    }
  56
+
  57
+    @Override
  58
+    public void postrun(int index, BenchmarkResult result) {}
  59
+
  60
+    @Override
  61
+    public void finish(boolean aborted) {}
  62
+}
14  src/dev/java/org/terasology/benchmark/chunks/arrays/TeraArraysBenchmark.java
... ...
@@ -1,11 +1,15 @@
1 1
 package org.terasology.benchmark.chunks.arrays;
2 2
 
  3
+import java.io.ByteArrayOutputStream;
3 4
 import java.util.LinkedList;
4 5
 import java.util.List;
5 6
 
6 7
 import org.terasology.benchmark.Benchmark;
7 8
 import org.terasology.benchmark.PrintToConsoleCallback;
8 9
 import org.terasology.benchmark.Benchmarks;
  10
+import org.terasology.utilities.FastRandom;
  11
+import org.terasology.world.chunks.blockdata.TeraArray;
  12
+import org.terasology.world.chunks.blockdata.TeraDenseArray16Bit;
9 13
 import org.terasology.world.chunks.blockdata.TeraDenseArray4Bit;
10 14
 import org.terasology.world.chunks.blockdata.TeraDenseArray8Bit;
11 15
 import org.terasology.world.chunks.blockdata.TeraSparseArray4Bit;
@@ -40,7 +44,15 @@ private TeraArraysBenchmark() {}
40 44
     public static void main(String[] args) {
41 45
 
42 46
         final List<Benchmark> benchmarks = new LinkedList<Benchmark>();
43  
-
  47
+        
  48
+//        benchmarks.add(new BenchmarkTeraArraySerializeObject(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16)));
  49
+//        benchmarks.add(new BenchmarkTeraArraySerializeToBuffer(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16)));
  50
+//        benchmarks.add(new BenchmarkTeraArraySerializeToStreamViaByteArray(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16)));
  51
+//        benchmarks.add(new BenchmarkTeraArraySerializeToStreamViaChannel(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16)));
  52
+//
  53
+//        benchmarks.add(new BenchmarkTeraArrayDeserializeFromBuffer(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16)));
  54
+//
  55
+//
44 56
 //        benchmarks.add(new BenchmarkTeraArrayRead(new TeraDenseArray8Bit(16, 256, 16)));
45 57
 //        benchmarks.add(new BenchmarkTeraArrayRead(new TeraDenseArray4Bit(16, 256, 16)));
46 58
 //        benchmarks.add(new BenchmarkTeraArrayRead(new TeraSparseArray8Bit(16, 256, 16, inflated8Bit, deflated8Bit)));
18  src/main/java/org/terasology/config/AdvancedConfig.java
@@ -6,7 +6,7 @@
6 6
 
7 7
 import org.slf4j.Logger;
8 8
 import org.slf4j.LoggerFactory;
9  
-import org.terasology.world.chunks.blockdata.TeraArrayFactory;
  9
+import org.terasology.world.chunks.blockdata.TeraArray;
10 10
 import org.terasology.world.chunks.blockdata.TeraDenseArray16Bit;
11 11
 import org.terasology.world.chunks.blockdata.TeraDenseArray4Bit;
12 12
 import org.terasology.world.chunks.blockdata.TeraDenseArray8Bit;
@@ -34,7 +34,7 @@
34 34
 public final class AdvancedConfig {
35 35
     
36 36
     private static final Logger logger = LoggerFactory.getLogger(AdvancedConfig.class);
37  
-    private static final Map<String, TeraArrayFactory> teraArrayRegistry; 
  37
+    private static final Map<String, TeraArray.Factory> teraArrayRegistry; 
38 38
 
39 39
     private String blocksFactory, sunlightFactory, lightFactory, liquidFactory;
40 40
     private boolean chunkDeflationEnabled, chunkDeflationLoggingEnabled;
@@ -45,7 +45,7 @@ public String getBlocksFactoryName() {
45 45
         return blocksFactory;
46 46
     }
47 47
     
48  
-    public TeraArrayFactory getBlocksFactory() {
  48
+    public TeraArray.Factory getBlocksFactory() {
49 49
         return requireTeraArrayFactory(blocksFactory);
50 50
     }
51 51
     
@@ -68,7 +68,7 @@ public String getSunlightFactoryName() {
68 68
         return sunlightFactory;
69 69
     }
70 70
     
71  
-    public TeraArrayFactory getSunlightFactory() {
  71
+    public TeraArray.Factory getSunlightFactory() {
72 72
         return requireTeraArrayFactory(sunlightFactory);
73 73
     }
74 74
     
@@ -91,7 +91,7 @@ public String getLightFactoryName() {
91 91
         return lightFactory;
92 92
     }
93 93
     
94  
-    public TeraArrayFactory getLightFactory() {
  94
+    public TeraArray.Factory getLightFactory() {
95 95
         return requireTeraArrayFactory(lightFactory);
96 96
     }
97 97
     
@@ -114,7 +114,7 @@ public String getLiquidFactoryName() {
114 114
         return liquidFactory;
115 115
     }
116 116
     
117  
-    public TeraArrayFactory getLiquidFactory() {
  117
+    public TeraArray.Factory getLiquidFactory() {
118 118
         return requireTeraArrayFactory(liquidFactory);
119 119
     }
120 120
     
@@ -200,12 +200,12 @@ public JsonElement serialize(AdvancedConfig src, Type typeOfSrc, JsonSerializati
200 200
         registerTeraArrayFactory(new TeraSparseArray16Bit.Factory());
201 201
     }
202 202
     
203  
-    public static TeraArrayFactory getTeraArrayFactory(String factory) {
  203
+    public static TeraArray.Factory getTeraArrayFactory(String factory) {
204 204
         Preconditions.checkNotNull(factory, "The parameter 'factory' must not be null");
205 205
         return teraArrayRegistry.get(factory);
206 206
     }
207 207
     
208  
-    public static TeraArrayFactory requireTeraArrayFactory(String factory) {
  208
+    public static TeraArray.Factory requireTeraArrayFactory(String factory) {
209 209
         Preconditions.checkNotNull(factory, "Parameter 'factory' must no be null");
210 210
         return Preconditions.checkNotNull(teraArrayRegistry.get(factory), "Factory does not exist: '" + factory + "'");
211 211
     }
@@ -230,7 +230,7 @@ public static boolean containsTeraArrayFactory(String factory) {
230 230
         return factories;
231 231
     }
232 232
     
233  
-    public static void registerTeraArrayFactory(TeraArrayFactory factory) {
  233
+    public static void registerTeraArrayFactory(TeraArray.Factory factory) {
234 234
         Preconditions.checkNotNull(factory, "Parameter 'factory' must not be null");
235 235
         final String name = factory.getArrayClass().getName();
236 236
         Preconditions.checkNotNull(name, "Factory:getName() must not return null");
20  src/main/java/org/terasology/io/SerializationHandler.java
... ...
@@ -0,0 +1,20 @@
  1
+package org.terasology.io;
  2
+
  3
+import java.nio.ByteBuffer;
  4
+
  5
+/**
  6
+ * The basic interface for serialization handlers.
  7
+ * 
  8
+ * @author Manuel Brotz <manu.brotz@gmx.ch>
  9
+ *
  10
+ */
  11
+public interface SerializationHandler<T> {
  12
+
  13
+    public boolean canHandle(Class<?> clazz);
  14
+    
  15
+    public int computeMinimumBufferSize(T object);
  16
+
  17
+    public ByteBuffer serialize(T object, ByteBuffer buffer);
  18
+    
  19
+    public T deserialize(ByteBuffer buffer);
  20
+}
106  src/main/java/org/terasology/world/chunks/blockdata/TeraArray.java
... ...
@@ -1,13 +1,11 @@
1 1
 package org.terasology.world.chunks.blockdata;
2 2
 
3  
-import java.io.DataInputStream;
4  
-import java.io.DataOutputStream;
5 3
 import java.io.Externalizable;
6 4
 import java.io.IOException;
7  
-import java.io.InputStream;
8 5
 import java.io.ObjectInput;
9 6
 import java.io.ObjectOutput;
10  
-import java.io.OutputStream;
  7
+import java.nio.BufferUnderflowException;
  8
+import java.nio.ByteBuffer;
11 9
 
12 10
 import org.terasology.world.chunks.deflate.TeraVisitingDeflator;
13 11
 
@@ -50,7 +48,42 @@ protected final int pos(int x, int z) {
50 48
     
51 49
     protected abstract void initialize();
52 50
     
53  
-    
  51
+    /**
  52
+     * This is the interface for tera array factories. Every tera array is required to implement a factory.
  53
+     * It should be implemented as a static subclass of the corresponding tera array class and it should be called Factory.
  54
+     *  
  55
+     * @author Manuel Brotz <manu.brotz@gmx.ch>
  56
+     * @see org.terasology.world.chunks.blockdata.TeraDenseArray16Bit.Factory
  57
+     *
  58
+     */
  59
+    public static interface Factory<T extends TeraArray> {
  60
+
  61
+        public Class<T> getArrayClass();
  62
+
  63
+        public T create();
  64
+        
  65
+        public T create(int sizeX, int sizeY, int sizeZ);
  66
+        
  67
+    }
  68
+
  69
+    /**
  70
+     * This is the interface for serialization handlers for tera arrays. Every tera array is required to implement
  71
+     * a serialization handler. It is recommended to subclass {@link org.terasology.world.chunks.blockdata.TeraArray.BasicSerializationHandler TeraArray.BasicSerializationHandler}
  72
+     * instead of using this interface directly. It should be implemented as a static subclass of the corresponding tera array class. 
  73
+     * 
  74
+     * @author Manuel Brotz <manu.brotz@gmx.ch>
  75
+     * @see org.terasology.world.chunks.blockdata.TeraArray.BasicSerializationHandler
  76
+     */
  77
+    public static interface SerializationHandler<T extends TeraArray> extends org.terasology.io.SerializationHandler<T> {
  78
+        
  79
+        public int computeMinimumBufferSize(T array);
  80
+
  81
+        public ByteBuffer serialize(T array, ByteBuffer buffer);
  82
+        
  83
+        public T deserialize(ByteBuffer buffer);
  84
+        
  85
+    }
  86
+
54 87
     /**
55 88
      * Extending this class is the recommended way to implement serialization handlers for tera arrays.
56 89
      * Tera arrays should implement their serialization handlers as a static subclass called SerializationHandler.
@@ -60,47 +93,50 @@ protected final int pos(int x, int z) {
60 93
      * @see org.terasology.world.chunks.blockdata.TeraDenseArray16Bit.Factory
61 94
      *
62 95
      */
63  
-    protected static abstract class SerializationHandler<T extends TeraArray> implements TeraArraySerializationHandler<T> {
  96
+    protected static abstract class BasicSerializationHandler<T extends TeraArray> implements SerializationHandler<T> {
64 97
 
65  
-        protected abstract void internalSerialize(T array, DataOutputStream out) throws IOException;
  98
+        protected abstract int internalComputeMinimumBufferSize(T array);
66 99
         
67  
-        protected abstract void internalDeserialize(T array, DataInputStream in) throws IOException;
  100
+        protected abstract void internalSerialize(T array, ByteBuffer buffer);
  101
+        
  102
+        protected abstract T internalDeserialize(int sizeX, int sizeY, int sizeZ, ByteBuffer buffer);
68 103
 
69 104
         @Override
70  
-        public final void serialize(T array, OutputStream out) throws IOException {
  105
+        public final int computeMinimumBufferSize(T array) {
71 106
             Preconditions.checkNotNull(array, "The parameter 'array' must not be null");
72  
-            Preconditions.checkNotNull(out, "The parameter 'out' must not be null");
73  
-            final DataOutputStream dout = new DataOutputStream(out);
74  
-            try {
75  
-                dout.writeInt(array.sizeX);
76  
-                dout.writeInt(array.sizeY);
77  
-                dout.writeInt(array.sizeZ);
78  
-                internalSerialize(array, dout);
79  
-                dout.flush();
80  
-            } finally {
81  
-                dout.close();
  107
+            return 16 + internalComputeMinimumBufferSize(array);
  108
+        }
  109
+        
  110
+        @Override
  111
+        public final ByteBuffer serialize(T array, ByteBuffer buffer) {
  112
+            Preconditions.checkNotNull(array, "The parameter 'array' must not be null");
  113
+            Preconditions.checkArgument(canHandle(array.getClass()), "Unable to handle the supplied array (" + array.getClass().getName() + ")");
  114
+            if (buffer == null) {
  115
+                buffer = ByteBuffer.allocateDirect(computeMinimumBufferSize(array));
82 116
             }
  117
+            final int lengthPos = buffer.position();
  118
+            buffer.putInt(0);
  119
+            buffer.putInt(array.getSizeX());
  120
+            buffer.putInt(array.getSizeY());
  121
+            buffer.putInt(array.getSizeZ());
  122
+            internalSerialize(array, buffer);
  123
+            buffer.putInt(lengthPos, buffer.position() - lengthPos - 4);
  124
+            return buffer;
83 125
         }
84 126
 
85 127
         @Override
86  
-        public final T deserialize(TeraArrayFactory<T> factory, InputStream in) throws IOException {
87  
-            Preconditions.checkNotNull(factory, "The parameter 'factory' must not be null");
88  
-            Preconditions.checkNotNull(in, "The parameter 'in' must not be null");
89  
-            final DataInputStream din = new DataInputStream(in);
90  
-            try {
91  
-                int sizeX = din.readInt();
92  
-                int sizeY = din.readInt();
93  
-                int sizeZ = din.readInt();
94  
-                T array = Preconditions.checkNotNull(factory.create(sizeX, sizeY, sizeZ), "TeraArrayFactory<T>:create(int, int, int) must not return null");
95  
-                internalDeserialize(array, din);
96  
-                return array;
97  
-            } finally {
98  
-                din.close();
99  
-            }
  128
+        public final T deserialize(ByteBuffer buffer) {
  129
+            Preconditions.checkNotNull(buffer, "The parameter 'buffer' must not be null");
  130
+            final int length = buffer.getInt();
  131
+            if (buffer.remaining() < length)
  132
+                throw new BufferUnderflowException();
  133
+            final int sizeX = buffer.getInt();
  134
+            final int sizeY = buffer.getInt();
  135
+            final int sizeZ = buffer.getInt();
  136
+            return internalDeserialize(sizeX, sizeY, sizeZ, buffer);
100 137
         }
101  
-        
102 138
     }
103  
-
  139
+    
104 140
     protected TeraArray() {}
105 141
 
106 142
     protected TeraArray(int sizeX, int sizeY, int sizeZ, boolean initialize) {
19  src/main/java/org/terasology/world/chunks/blockdata/TeraArrayFactory.java
... ...
@@ -1,19 +0,0 @@
1  
-package org.terasology.world.chunks.blockdata;
2  
-
3  
-/**
4  
- * This is the interface for tera array factories. Every tera array is required to implement a factory.
5  
- * It should be implemented as a static subclass of the corresponding tera array class and it should be called Factory.
6  
- *  
7  
- * @author Manuel Brotz <manu.brotz@gmx.ch>
8  
- * @see org.terasology.world.chunks.blockdata.TeraDenseArray16Bit.Factory
9  
- *
10  
- */
11  
-public interface TeraArrayFactory<T extends TeraArray> {
12  
-
13  
-    public Class<T> getArrayClass();
14  
-
15  
-    public T create();
16  
-    
17  
-    public T create(int sizeX, int sizeY, int sizeZ);
18  
-    
19  
-}
23  src/main/java/org/terasology/world/chunks/blockdata/TeraArraySerializationHandler.java
... ...
@@ -1,23 +0,0 @@
1  
-package org.terasology.world.chunks.blockdata;
2  
-
3  
-import java.io.IOException;
4  
-import java.io.InputStream;
5  
-import java.io.OutputStream;
6  
-
7  
-/**
8  
- * This is the interface for serialization handlers for tera arrays. Every tera array is required to implement
9  
- * a serialization handler. It is recommended to subclass {@link org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler TeraArray.SerializationHandler}
10  
- * instead of using this interface directly. It should be implemented as a static subclass of the corresponding tera array class. 
11  
- * 
12  
- * @author Manuel Brotz <manu.brotz@gmx.ch>
13  
- * @see org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler
14  
- */
15  
-public interface TeraArraySerializationHandler<T extends TeraArray> {
16  
-
17  
-    public Class<T> getArrayClass();
18  
-
19  
-    public void serialize(T array, OutputStream out) throws IOException;
20  
-    
21  
-    public T deserialize(TeraArrayFactory<T> factory, InputStream in) throws IOException;
22  
-    
23  
-}
56  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArray16Bit.java
... ...
@@ -1,10 +1,10 @@
1 1
 package org.terasology.world.chunks.blockdata;
2 2
 
3  
-import java.io.DataInputStream;
4  
-import java.io.DataOutputStream;
5 3
 import java.io.IOException;
6 4
 import java.io.ObjectInput;
7 5
 import java.io.ObjectOutput;
  6
+import java.nio.ByteBuffer;
  7
+import java.nio.ShortBuffer;
8 8
 
9 9
 import org.terasology.world.chunks.deflate.TeraVisitingDeflator;
10 10
 
@@ -26,45 +26,61 @@ protected void initialize() {
26 26
         this.data = new short[getSizeXYZ()];
27 27
     }
28 28
 
29  
-    public static class SerializationHandler extends TeraArray.SerializationHandler<TeraDenseArray16Bit> {
  29
+    public static class SerializationHandler extends TeraArray.BasicSerializationHandler<TeraDenseArray16Bit> {
  30
+
30 31
         @Override
31  
-        public Class<TeraDenseArray16Bit> getArrayClass() {
32  
-            return TeraDenseArray16Bit.class;
  32
+        public boolean canHandle(Class<?> clazz) {
  33
+            return TeraDenseArray16Bit.class.equals(clazz);
33 34
         }
  35
+
34 36
         @Override
35  
-        protected void internalSerialize(TeraDenseArray16Bit array, DataOutputStream out) throws IOException {
  37
+        protected int internalComputeMinimumBufferSize(TeraDenseArray16Bit array) {
  38
+            final short[] data = array.data;
  39
+            if (data == null)
  40
+                return 4;
  41
+            else 
  42
+                return 4 + data.length;
  43
+        }
  44
+
  45
+        @Override
  46
+        protected void internalSerialize(TeraDenseArray16Bit array, ByteBuffer buffer) {
36 47
             final short[] data = array.data;
37 48
             if (data == null) 
38  
-                out.writeInt(0);
  49
+                buffer.putInt(0);
39 50
             else {
40  
-                out.writeInt(data.length);
41  
-                for (short s : data) {
42  
-                    out.writeShort(s);
43  
-                }
  51
+                buffer.putInt(data.length);
  52
+                final ShortBuffer sbuffer = buffer.asShortBuffer();
  53
+                sbuffer.put(data);
  54
+                buffer.position(buffer.position() + data.length * 2);
44 55
             }
45 56
         }
  57
+
46 58
         @Override
47  
-        protected void internalDeserialize(TeraDenseArray16Bit array, DataInputStream in) throws IOException {
48  
-            final short[] data = array.data;
49  
-            final int length = in.readInt();
50  
-            Preconditions.checkNotNull(data);
51  
-            if (data.length != length)
52  
-                throw new IOException("The size of the array (" + data.length + ") does not match the size of the stored data (" + length + ")");
53  
-            for (int i = 0; i < length; i++) {
54  
-                data[i] = in.readShort();
  59
+        protected TeraDenseArray16Bit internalDeserialize(int sizeX, int sizeY, int sizeZ, ByteBuffer buffer) {
  60
+            final int length = buffer.getInt();
  61
+            if (length > 0) {
  62
+                final short[] data = new short[length];
  63
+                final ShortBuffer sbuffer = buffer.asShortBuffer();
  64
+                sbuffer.get(data, 0, length);
  65
+                buffer.position(buffer.position() + length * 2);
  66
+                return new TeraDenseArray16Bit(sizeX, sizeY, sizeZ, data);
55 67
             }
  68
+            return new TeraDenseArray16Bit(sizeX, sizeY, sizeZ);
56 69
         }
57 70
     }
58 71
     
59  
-    public static class Factory implements TeraArrayFactory<TeraDenseArray16Bit> {
  72
+    public static class Factory implements TeraArray.Factory<TeraDenseArray16Bit> {
  73
+        
60 74
         @Override
61 75
         public Class<TeraDenseArray16Bit> getArrayClass() {
62 76
             return TeraDenseArray16Bit.class;
63 77
         }
  78
+        
64 79
         @Override
65 80
         public TeraDenseArray16Bit create() {
66 81
             return new TeraDenseArray16Bit();
67 82
         }
  83
+        
68 84
         @Override
69 85
         public TeraDenseArray16Bit create(int sizeX, int sizeY, int sizeZ) {
70 86
             return new TeraDenseArray16Bit(sizeX, sizeY, sizeZ);
18  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArray4Bit.java
@@ -25,21 +25,33 @@ protected final int rowSize() {
25 25
     }
26 26
 
27 27
     public static class SerializationHandler extends TeraDenseArrayByte.SerializationHandler<TeraDenseArray4Bit> {
  28
+
28 29
         @Override
29  
-        public Class<TeraDenseArray4Bit> getArrayClass() {
30  
-            return TeraDenseArray4Bit.class;
  30
+        public boolean canHandle(Class<?> clazz) {
  31
+            return TeraDenseArray4Bit.class.equals(clazz);
  32
+        }
  33
+
  34
+        @Override
  35
+        protected TeraDenseArray4Bit createArray(int sizeX, int sizeY, int sizeZ, byte[] data) {
  36
+            if (data == null) 
  37
+                return new TeraDenseArray4Bit(sizeX, sizeY, sizeZ);
  38
+            else
  39
+                return new TeraDenseArray4Bit(sizeX, sizeY, sizeZ, data);
31 40
         }
32 41
     }
33 42
     
34  
-    public static class Factory implements TeraArrayFactory<TeraDenseArray4Bit> {
  43
+    public static class Factory implements TeraArray.Factory<TeraDenseArray4Bit> {
  44
+        
35 45
         @Override
36 46
         public Class<TeraDenseArray4Bit> getArrayClass() {
37 47
             return TeraDenseArray4Bit.class;
38 48
         }
  49
+        
39 50
         @Override
40 51
         public TeraDenseArray4Bit create() {
41 52
             return new TeraDenseArray4Bit();
42 53
         }
  54
+        
43 55
         @Override
44 56
         public TeraDenseArray4Bit create(int sizeX, int sizeY, int sizeZ) {
45 57
             return new TeraDenseArray4Bit(sizeX, sizeY, sizeZ);
18  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArray8Bit.java
@@ -25,21 +25,33 @@ protected final int rowSize() {
25 25
     }
26 26
 
27 27
     public static class SerializationHandler extends TeraDenseArrayByte.SerializationHandler<TeraDenseArray8Bit> {
  28
+
28 29
         @Override
29  
-        public Class<TeraDenseArray8Bit> getArrayClass() {
30  
-            return TeraDenseArray8Bit.class;
  30
+        public boolean canHandle(Class<?> clazz) {
  31
+            return TeraDenseArray8Bit.class.equals(clazz);
  32
+        }
  33
+
  34
+        @Override
  35
+        protected TeraDenseArray8Bit createArray(int sizeX, int sizeY, int sizeZ, byte[] data) {
  36
+            if (data == null)
  37
+                return new TeraDenseArray8Bit(sizeX, sizeY, sizeZ);
  38
+            else
  39
+                return new TeraDenseArray8Bit(sizeX, sizeY, sizeZ, data);
31 40
         }
32 41
     }
33 42
     
34  
-    public static class Factory implements TeraArrayFactory<TeraDenseArray8Bit> {
  43
+    public static class Factory implements TeraArray.Factory<TeraDenseArray8Bit> {
  44
+        
35 45
         @Override
36 46
         public Class<TeraDenseArray8Bit> getArrayClass() {
37 47
             return TeraDenseArray8Bit.class;
38 48
         }
  49
+        
39 50
         @Override
40 51
         public TeraDenseArray8Bit create() {
41 52
             return new TeraDenseArray8Bit();
42 53
         }
  54
+        
43 55
         @Override
44 56
         public TeraDenseArray8Bit create(int sizeX, int sizeY, int sizeZ) {
45 57
             return new TeraDenseArray8Bit(sizeX, sizeY, sizeZ);
43  src/main/java/org/terasology/world/chunks/blockdata/TeraDenseArrayByte.java
... ...
@@ -1,10 +1,9 @@
1 1
 package org.terasology.world.chunks.blockdata;
2 2
 
3  
-import java.io.DataInputStream;
4  
-import java.io.DataOutputStream;
5 3
 import java.io.IOException;
6 4
 import java.io.ObjectInput;
7 5
 import java.io.ObjectOutput;
  6
+import java.nio.ByteBuffer;
8 7
 
9 8
 import com.google.common.base.Preconditions;
10 9
 
@@ -32,29 +31,39 @@ protected void initialize() {
32 31
         this.data = new byte[dataSize()];
33 32
     }
34 33
     
35  
-    protected static abstract class SerializationHandler<T extends TeraDenseArrayByte> extends TeraArray.SerializationHandler<T> {
  34
+    protected static abstract class SerializationHandler<T extends TeraDenseArrayByte> extends TeraArray.BasicSerializationHandler<T> {
  35
+        
  36
+        protected abstract T createArray(int sizeX, int sizeY, int sizeZ, byte[] data);
  37
+        
36 38
         @Override
37  
-        protected void internalSerialize(T array, DataOutputStream out) throws IOException {
  39
+        protected int internalComputeMinimumBufferSize(T array) {
38 40
             final byte[] data = array.data;
39 41
             if (data == null)
40  
-                out.writeInt(0);
  42
+                return 4;
  43
+            else 
  44
+                return 4 + data.length;
  45
+        }
  46
+        
  47
+        @Override
  48
+        protected void internalSerialize(T array, ByteBuffer buffer) {
  49
+            final byte[] data = array.data;
  50
+            if (data == null)
  51
+                buffer.putInt(0);
41 52
             else {
42  
-                out.writeInt(data.length);
43  
-                for (byte b : data) {
44  
-                    out.writeByte(b);
45  
-                }
  53
+                buffer.putInt(data.length);
  54
+                buffer.put(data);
46 55
             }
47 56
         }
  57
+        
48 58
         @Override
49  
-        protected void internalDeserialize(T array, DataInputStream in) throws IOException {
50  
-            final byte[] data = array.data;
51  
-            final int length = in.readInt();
52  
-            Preconditions.checkNotNull(data);
53  
-            if (data.length != length)
54  
-                throw new IOException("The size of the array (" + data.length + ") does not match the size of the stored data (" + length + ")");
55  
-            for (int i = 0; i < length; i++) {
56  
-                data[i] = in.readByte();
  59
+        protected T internalDeserialize(int sizeX, int sizeY, int sizeZ, ByteBuffer buffer) {
  60
+            final int length = buffer.getInt();
  61
+            if (length > 0) {
  62
+                final byte[] data = new byte[length];
  63
+                buffer.get(data, 0, length);
  64
+                return createArray(sizeX, sizeY, sizeZ, data);
57 65
             }
  66
+            return createArray(sizeX, sizeY, sizeZ, null);
58 67
         }
59 68
     }
60 69
     
126  src/main/java/org/terasology/world/chunks/blockdata/TeraSparseArray16Bit.java
... ...
@@ -1,10 +1,10 @@
1 1
 package org.terasology.world.chunks.blockdata;
2 2
 
3  
-import java.io.DataInputStream;
4  
-import java.io.DataOutputStream;
5 3
 import java.io.IOException;
6 4
 import java.io.ObjectInput;
7 5
 import java.io.ObjectOutput;
  6
+import java.nio.ByteBuffer;
  7
+import java.nio.ShortBuffer;
8 8
 import java.util.Arrays;
9 9
 
10 10
 import org.terasology.world.chunks.deflate.TeraVisitingDeflator;
@@ -27,80 +27,102 @@
27 27
     
28 28
     @Override
29 29
     protected void initialize() {}
  30
+    
  31
+    public static class SerializationHandler extends TeraArray.BasicSerializationHandler<TeraSparseArray16Bit> {
30 32
 
31  
-    public static class SerializationHandler extends TeraArray.SerializationHandler<TeraSparseArray16Bit> {
  33
+        private void putRow(final short[] row, final int length, final ByteBuffer buffer) {
  34
+            final ShortBuffer sbuffer = buffer.asShortBuffer();
  35
+            sbuffer.put(row, 0, length);
  36
+            buffer.position(buffer.position() + length * 2);
  37
+        }
  38
+        
  39
+        private void getRow(final short[] row, final int length, final ByteBuffer buffer) {
  40
+            final ShortBuffer sbuffer = buffer.asShortBuffer();
  41
+            sbuffer.get(row, 0, length);
  42
+            buffer.position(buffer.position() + length * 2);
  43
+        }
  44
+        
32 45
         @Override
33  
-        public Class<TeraSparseArray16Bit> getArrayClass() {
34  
-            return TeraSparseArray16Bit.class;
  46
+        public boolean canHandle(Class<?> clazz) {
  47
+            return TeraSparseArray16Bit.class.equals(clazz);
  48
+        }
  49
+
  50
+        @Override
  51
+        protected int internalComputeMinimumBufferSize(TeraSparseArray16Bit array) {
  52
+            final short[][] inf = array.inflated;
  53
+            if (inf == null) 
  54
+                return 3;
  55
+            else {
  56
+                final int sizeY = array.getSizeY(), rowSize = array.getSizeXZ() * 2;
  57
+                int result = 1;
  58
+                for (int y = 0; y < sizeY; y++) 
  59
+                    if (inf[y] == null)
  60
+                        result += 3;
  61
+                    else
  62
+                        result += 1 + rowSize;
  63
+                return result;
  64
+            }
35 65
         }
  66
+
36 67
         @Override
37  
-        protected void internalSerialize(TeraSparseArray16Bit array, DataOutputStream out) throws IOException {
38  
-            final short[][] inflated = array.inflated;
39  
-            if (inflated == null) {
40  
-                out.writeBoolean(false);
41  
-                out.writeShort(array.fill);
  68
+        protected void internalSerialize(TeraSparseArray16Bit array, ByteBuffer buffer) {
  69
+            final short[][] inf = array.inflated;
  70
+            if (inf == null) {
  71
+                buffer.put((byte) 0);
  72
+                buffer.putShort(array.fill);
42 73
             } else {
43  
-                final short[] deflated = array.deflated;
44  
-                final int sizeY = array.getSizeY();
45  
-                final int rowlen = array.getSizeXZ();
46  
-                out.writeBoolean(true);
47  
-                int rows = 0;
48  
-                for (final short[] row : inflated) {if (row != null) rows++;}
49  
-                out.writeInt(rows);
50