Move ColumnRenderSource file parsing into ColumnRenderLoader

This commit is contained in:
James Seibel
2023-01-13 07:50:21 -06:00
parent 7ea614f257
commit a27e9bac0c
3 changed files with 90 additions and 58 deletions
@@ -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);
@@ -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. <br><br>
*
* 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;
}
}
}
@@ -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)
{