diff --git a/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java b/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java index dd96472a9..f3443f0be 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java @@ -93,7 +93,12 @@ public abstract class AbstractRenderSourceLoader LOADER_BY_SOURCE_TYPE.put(renderSourceClass, this); } - /** Can return null if the file is out of date or something */ + /** + * Can return null if the file is out of date. + * + * @throws IOException if the file uses a unsupported data version + * or there was an issue reading the file + */ public abstract ILodRenderSource loadRenderSource(RenderMetaDataFile renderFile, InputStream data, IDhLevel level) throws IOException; /** Should not return null */ public abstract ILodRenderSource createRenderSource(ILodDataSource dataSource, IDhClientLevel level); diff --git a/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderLoader.java b/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderLoader.java index 222ab2b58..52fc1d5ae 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderLoader.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderLoader.java @@ -2,6 +2,7 @@ package com.seibel.lod.core.datatype.column; import com.seibel.lod.core.datatype.IIncompleteDataSource; import com.seibel.lod.core.datatype.ILodDataSource; +import com.seibel.lod.core.datatype.column.accessor.ColumnFormat; import com.seibel.lod.core.datatype.full.FullDataSource; import com.seibel.lod.core.datatype.transform.FullToColumnTransformer; import com.seibel.lod.core.level.IDhClientLevel; @@ -14,9 +15,14 @@ import com.seibel.lod.core.util.LodUtil; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** - * Can load {@link ColumnRenderSource}'s for the {@link ColumnRenderSource#LATEST_VERSION} + * Handles loading and parsing {@link RenderMetaDataFile}s to create {@link ColumnRenderSource}s.

+ * + * Please see the {@link ColumnRenderLoader#loadRenderSource} method to see what + * file versions this class can handle. */ public class ColumnRenderLoader extends AbstractRenderSourceLoader { @@ -30,8 +36,16 @@ public class ColumnRenderLoader extends AbstractRenderSourceLoader @Override public ILodRenderSource loadRenderSource(RenderMetaDataFile dataFile, InputStream data, IDhLevel level) throws IOException { - DataInputStream inputStream = new DataInputStream(data); // DO NOT CLOSE - return new ColumnRenderSource(dataFile.pos, inputStream, dataFile.metaData.loaderVersion, level); + DataInputStream inputStream = new DataInputStream(data); // DO NOT CLOSE + int dataFileVersion = dataFile.metaData.loaderVersion; + + switch (dataFileVersion) + { + case 1: + return new ColumnRenderSource(dataFile.pos, readDataV1(inputStream, level.getMinY()), level); + default: + throw new IOException("Invalid Data: The data version [" + dataFileVersion + "] is not supported"); + } } @Override @@ -49,4 +63,66 @@ public class ColumnRenderLoader extends AbstractRenderSourceLoader return null; } + + + //========================// + // versioned file parsing // + //========================// + + /** + * @param inputData Expected format: 1st byte: detail level, 2nd byte: vertical size, 3rd byte on: column data + * + * @throws IOException if there was an issue reading the stream + */ + private static ParsedColumnData readDataV1(DataInputStream inputData, int yOffset) throws IOException + { + byte detailLevel = inputData.readByte(); + int verticalDataCount = inputData.readByte() & 0b01111111; + + int maxNumberOfDataPoints = ColumnRenderSource.SECTION_SIZE * ColumnRenderSource.SECTION_SIZE * verticalDataCount; + + + //FIXME: Temp hack flag for marking a empty section + short tempMinHeight = Short.reverseBytes(inputData.readShort()); + if (tempMinHeight == Short.MAX_VALUE) + { + return new ParsedColumnData(detailLevel, verticalDataCount, new long[maxNumberOfDataPoints], true); + } + + + // isEmpty = false + byte[] data = new byte[maxNumberOfDataPoints * Long.BYTES]; + ByteBuffer byteBuffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); + inputData.readFully(data); + + long[] dataPoints = new long[maxNumberOfDataPoints]; + byteBuffer.asLongBuffer().get(dataPoints); + if (tempMinHeight != yOffset) + { + for (int i = 0; i < dataPoints.length; i++) + { + dataPoints[i] = ColumnFormat.shiftHeightAndDepth(dataPoints[i], (short) (tempMinHeight - yOffset)); + } + } + + return new ParsedColumnData(detailLevel, verticalDataCount, dataPoints, false); + } + + public static class ParsedColumnData + { + byte detailLevel; + int verticalSize; + long[] dataContainer; + boolean isEmpty; + + public ParsedColumnData(byte detailLevel, int verticalSize, long[] dataContainer, boolean isEmpty) + { + this.detailLevel = detailLevel; + this.verticalSize = verticalSize; + this.dataContainer = dataContainer; + this.isEmpty = isEmpty; + } + } + + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderSource.java b/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderSource.java index 2f034e55f..403582804 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderSource.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/column/ColumnRenderSource.java @@ -19,12 +19,9 @@ import com.seibel.lod.core.util.objects.Reference; import com.seibel.lod.core.util.LodUtil; import org.apache.logging.log4j.Logger; -import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; @@ -88,23 +85,21 @@ public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype } /** - * Creates a new ColumnRenderSource with data from the given DataInputStream. + * Creates a new ColumnRenderSource from the parsedColumnData. * - * @param inputData Expected format: 1st byte: detail level, 2nd byte: vertical size, 3rd byte on: column data * @throws IOException if the DataInputStream's detail level isn't what was expected */ - public ColumnRenderSource(DhSectionPos sectionPos, DataInputStream inputData, int version, IDhLevel level) throws IOException + public ColumnRenderSource(DhSectionPos sectionPos, ColumnRenderLoader.ParsedColumnData parsedColumnData, IDhLevel level) throws IOException { - byte detailLevel = inputData.readByte(); - if (sectionPos.sectionDetail - SECTION_SIZE_OFFSET != detailLevel) + if (sectionPos.sectionDetail - SECTION_SIZE_OFFSET != parsedColumnData.detailLevel) { throw new IOException("Invalid data: detail level does not match"); } this.sectionPos = sectionPos; this.yOffset = level.getMinY(); - this.verticalSize = inputData.readByte() & 0b01111111; - this.dataContainer = this.loadData(inputData, version, this.verticalSize); + this.verticalSize = parsedColumnData.verticalSize; + this.dataContainer = parsedColumnData.dataContainer; this.airDataContainer = new int[AIR_SECTION_SIZE * AIR_SECTION_SIZE * this.verticalSize]; this.debugSourceFlags = new DebugSourceFlag[SECTION_SIZE * SECTION_SIZE]; @@ -117,50 +112,6 @@ public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype // datapoint manipulation // //========================// - /** - * Attempts to parse and load the given DataInputStream based on its - * render data version - * - * @throws IOException if the version isn't supported - */ - private long[] loadData(DataInputStream inputData, int version, int verticalSize) throws IOException - { - switch (version) - { - case 1: - return this.readDataV1(inputData, verticalSize); - default: - throw new IOException("Invalid Data: The data version [" + version + "] is not supported"); - } - } - - private static long[] readDataV1(DataInputStream inputData, int tempMaxVerticalData) throws IOException - { - int maxNumberOfDataPoints = SECTION_SIZE * SECTION_SIZE * tempMaxVerticalData; - - short tempMinHeight = Short.reverseBytes(inputData.readShort()); - if (tempMinHeight == Short.MAX_VALUE) - { //FIXME: Temp hack flag for marking a empty section - return new long[maxNumberOfDataPoints]; - } - - this.isEmpty = false; - byte[] data = new byte[maxNumberOfDataPoints * Long.BYTES]; - ByteBuffer byteBuffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); - inputData.readFully(data); - - long[] result = new long[maxNumberOfDataPoints]; - byteBuffer.asLongBuffer().get(result); - if (tempMinHeight != this.yOffset) - { - for (int i = 0; i < result.length; i++) - { - result[i] = ColumnFormat.shiftHeightAndDepth(result[i], (short) (tempMinHeight - this.yOffset)); - } - } - return result; - } - @Override public void clearDataPoint(int posX, int posZ) {