Refactor ColumnRenderSource

This commit is contained in:
James Seibel
2022-10-05 22:21:10 -05:00
parent ce991cd912
commit 2ec7cc8c6d
9 changed files with 310 additions and 215 deletions
@@ -43,6 +43,6 @@ public interface ILodRenderSource
void fastWrite(ChunkSizedData chunkData, IDhClientLevel level);
/** Only override the data that has not been written directly using write(), and skip those that are empty */
void weakWrite(ILodRenderSource source);
/** Overrides any data that has not been written directly using write(). Skips empty source dataPoints. */
void updateFromRenderSource(ILodRenderSource source);
}
@@ -57,7 +57,7 @@ public class PlaceHolderRenderSource implements ILodRenderSource
public void fastWrite(ChunkSizedData chunkData, IDhClientLevel level) { /* TODO */ }
@Override
public void weakWrite(ILodRenderSource source) { /* TODO */ }
public void updateFromRenderSource(ILodRenderSource source) { /* TODO */ }
}
@@ -28,10 +28,14 @@ import java.nio.ByteOrder;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Leetom
* @version 2022-10-5
*/
public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final boolean DO_SAFETY_CHECKS = true;
public static final boolean DO_SAFETY_CHECKS = true; // TODO: this could potentially be replaced with "ModInfo.IS_DEV_BUILD"
public static final byte SECTION_SIZE_OFFSET = 6;
public static final int SECTION_SIZE = 1 << SECTION_SIZE_OFFSET;
public static final byte LATEST_VERSION = 1;
@@ -98,29 +102,24 @@ public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype
this.sectionPos = sectionPos;
this.yOffset = level.getMinY();
this.verticalSize = inputData.readByte() & 0b01111111;
this.dataContainer = loadData(inputData, version, this.verticalSize);
this.dataContainer = this.loadData(inputData, version, this.verticalSize);
this.airDataContainer = new int[AIR_SECTION_SIZE * AIR_SECTION_SIZE * this.verticalSize];
this.debugSourceFlags = new DebugSourceFlag[SECTION_SIZE * SECTION_SIZE];
debugFillFlag(0, 0, SECTION_SIZE, SECTION_SIZE, DebugSourceFlag.FILE);
this.fillDebugFlag(0, 0, SECTION_SIZE, SECTION_SIZE, DebugSourceFlag.FILE);
}
//========================//
// datapoint manipulation //
//========================//
public void debugFillFlag(int ox, int oz, int w, int h, DebugSourceFlag flag)
{
for (int x = ox; x < ox + w; x++)
{
for (int z = oz; z < oz + h; z++)
{
debugSourceFlags[x * SECTION_SIZE + z] = flag;
}
}
}
public DebugSourceFlag debugGetFlag(int ox, int oz) { return debugSourceFlags[ox * SECTION_SIZE + oz]; }
/**
* Attempts to parse and load the given DataInputStream.
*
* @throws IOException if the version isn't supported
*/
private long[] loadData(DataInputStream inputData, int version, int verticalSize) throws IOException
{
switch (version)
@@ -128,65 +127,69 @@ public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype
case 1:
return readDataV1(inputData, verticalSize);
default:
throw new IOException("Invalid Data: The version of the data is not supported");
throw new IOException("Invalid Data: The data version [" + version + "] is not supported");
}
}
private long[] readDataV1(DataInputStream inputData, int tempMaxVerticalData) throws IOException
{
int x = SECTION_SIZE * SECTION_SIZE * tempMaxVerticalData;
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[x];
return new long[maxNumberOfDataPoints];
}
isEmpty = false;
byte[] data = new byte[x * Long.BYTES];
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
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[x];
bb.asLongBuffer().get(result);
if (tempMinHeight != yOffset)
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 - yOffset));
result[i] = ColumnFormat.shiftHeightAndDepth(result[i], (short) (tempMinHeight - this.yOffset));
}
}
return result;
}
@Override
public void clear(int posX, int posZ)
public void clearDataPoint(int posX, int posZ)
{
for (int verticalIndex = 0; verticalIndex < verticalSize; verticalIndex++)
dataContainer[posX * SECTION_SIZE * verticalSize + posZ * verticalSize + verticalIndex] =
ColumnFormat.EMPTY_DATA;
for (int verticalIndex = 0; verticalIndex < this.verticalSize; verticalIndex++)
{
this.dataContainer[posX * SECTION_SIZE * this.verticalSize + posZ * this.verticalSize + verticalIndex] = ColumnFormat.EMPTY_DATA;
}
}
@Override
public boolean addData(long data, int posX, int posZ, int verticalIndex)
public boolean setDataPoint(long data, int posX, int posZ, int verticalIndex)
{
dataContainer[posX * SECTION_SIZE * verticalSize + posZ * verticalSize + verticalIndex] = data;
this.dataContainer[posX * SECTION_SIZE * this.verticalSize + posZ * this.verticalSize + verticalIndex] = data;
return true;
}
@Override
public boolean copyVerticalData(IColumnDataView data, int posX, int posZ, boolean override)
public boolean copyVerticalData(IColumnDataView newData, int posX, int posZ, boolean overwriteDataWithSameGenerationMode)
{
if (DO_SAFETY_CHECKS)
{
if (data.size() != verticalSize)
throw new IllegalArgumentException("data size not the same as vertical size");
if (newData.size() != this.verticalSize)
throw new IllegalArgumentException("newData size not the same as this column's vertical size");
if (posX < 0 || posX >= SECTION_SIZE)
throw new IllegalArgumentException("X position is out of bounds");
if (posZ < 0 || posZ >= SECTION_SIZE)
throw new IllegalArgumentException("Z position is out of bounds");
}
int index = posX * SECTION_SIZE * verticalSize + posZ * verticalSize;
int compare = ColumnFormat.compareDatapointPriority(data.get(0), dataContainer[index]);
if (override)
int dataOffset = posX * SECTION_SIZE * this.verticalSize + posZ * this.verticalSize;
int compare = ColumnFormat.compareDatapointPriority(newData.get(0), this.dataContainer[dataOffset]);
if (overwriteDataWithSameGenerationMode)
{
if (compare < 0)
return false;
@@ -196,146 +199,198 @@ public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype
if (compare <= 0)
return false;
}
data.copyTo(dataContainer, index, data.size());
// copy the newData into this column's data
newData.copyTo(this.dataContainer, dataOffset, newData.size());
return true;
}
@Override
public long getData(int posX, int posZ, int verticalIndex) { return dataContainer[posX * SECTION_SIZE * verticalSize + posZ * verticalSize + verticalIndex]; }
// TODO:
@Override
public long[] getAllData(int posX, int posZ)
public long getDataPoint(int posX, int posZ, int verticalIndex) { return this.dataContainer[posX * SECTION_SIZE * this.verticalSize + posZ * this.verticalSize + verticalIndex]; }
@Override
public long[] getVerticalDataPointArray(int posX, int posZ)
{
long[] result = new long[verticalSize];
int index = posX * SECTION_SIZE * verticalSize + posZ * verticalSize;
System.arraycopy(dataContainer, index, result, 0, verticalSize);
long[] result = new long[this.verticalSize];
int index = posX * SECTION_SIZE * this.verticalSize + posZ * this.verticalSize;
System.arraycopy(this.dataContainer, index, result, 0, this.verticalSize);
return result;
}
@Override
public ColumnArrayView getVerticalDataView(int posX, int posZ)
public ColumnArrayView getVerticalDataPointView(int posX, int posZ)
{
return new ColumnArrayView(dataContainer, verticalSize,
posX * SECTION_SIZE * verticalSize + posZ * verticalSize, verticalSize);
return new ColumnArrayView(this.dataContainer, this.verticalSize,
posX * SECTION_SIZE * this.verticalSize + posZ * this.verticalSize,
this.verticalSize);
}
@Override
public ColumnQuadView getDataInQuad(int quadX, int quadZ, int quadXSize, int quadZSize) { return new ColumnQuadView(dataContainer, SECTION_SIZE, verticalSize, quadX, quadZ, quadXSize, quadZSize); }
public ColumnQuadView getFullQuadView() { return getQuadViewOverRange(0, 0, SECTION_SIZE, SECTION_SIZE); }
@Override
public ColumnQuadView getQuadViewOverRange(int quadX, int quadZ, int quadXSize, int quadZSize) { return new ColumnQuadView(this.dataContainer, SECTION_SIZE, this.verticalSize, quadX, quadZ, quadXSize, quadZSize); }
@Override
public ColumnQuadView getFullQuad() { return new ColumnQuadView(dataContainer, SECTION_SIZE, verticalSize, 0, 0, SECTION_SIZE, SECTION_SIZE); }
public int getVerticalSize() { return this.verticalSize; }
//========================//
// data update and output //
//========================//
/** @return true if this object had data written in every column */
boolean writeData(DataOutputStream outputStream) throws IOException
{
outputStream.writeByte(getDataDetail());
outputStream.writeByte((byte) this.verticalSize);
if (isEmpty)
{
outputStream.writeByte(Short.MAX_VALUE & 0xFF);
outputStream.writeByte((Short.MAX_VALUE >> 8) & 0xFF);
return false;
}
else
{
// FIXME: yOffset is a int, but we only are writing a short.
outputStream.writeByte((byte) (this.yOffset & 0xFF));
outputStream.writeByte((byte) ((this.yOffset >> 8) & 0xFF));
// write the data for each column
boolean allGenerated = true;
for (int x = 0; x < SECTION_SIZE * SECTION_SIZE; x++)
{
for (int z = 0; z < verticalSize; z++)
{
long currentDatapoint = dataContainer[x * verticalSize + z];
if (ColumnFormat.doesDataPointExist(currentDatapoint))
{
// TODO: the "1" is a placeholder debug line
currentDatapoint = ColumnFormat.overrideGenerationMode(currentDatapoint, (byte) 1);
}
outputStream.writeLong(Long.reverseBytes(currentDatapoint));
}
if (!ColumnFormat.doesDataPointExist(dataContainer[x]))
{
allGenerated = false;
}
}
return allGenerated;
}
}
@Override
public int getVerticalSize() { return verticalSize; }
public void updateFromRenderSource(ILodRenderSource source)
{
// TODO if we can only write this one type of data isn't it dangerous to have it in the interface?
LodUtil.assertTrue(source instanceof ColumnRenderSource);
ColumnRenderSource src = (ColumnRenderSource) source;
// validate we are writing for the same location
LodUtil.assertTrue(src.sectionPos.equals(this.sectionPos));
// validate both objects have the same number of dataPoints
LodUtil.assertTrue(src.verticalSize == this.verticalSize);
if (src.isEmpty)
// the source is empty, don't attempt to update anything
return;
// the source isn't empty, this object won't be empty after the method finishes
this.isEmpty = false;
for (int i = 0; i < this.dataContainer.length; i += this.verticalSize)
{
int thisGenMode = ColumnFormat.getGenerationMode(this.dataContainer[i]);
int srcGenMode = ColumnFormat.getGenerationMode(src.dataContainer[i]);
if (srcGenMode == 0)
// the source hasn't been generated, don't write it
continue;
// this object's column is older than the source's column, update it
if (thisGenMode <= srcGenMode)
{
ColumnArrayView thisColumnArrayView = new ColumnArrayView(this.dataContainer, this.verticalSize, i, this.verticalSize);
ColumnArrayView srcColumnArrayView = new ColumnArrayView(src.dataContainer, src.verticalSize, i, src.verticalSize);
thisColumnArrayView.copyFrom(srcColumnArrayView);
this.debugSourceFlags[i / this.verticalSize] = src.debugSourceFlags[i / this.verticalSize];
}
}
}
@Override
public boolean doesItExist(int posX, int posZ) { return ColumnFormat.doesItExist(getSingleData(posX, posZ)); }
public void fastWrite(ChunkSizedData chunkData, IDhClientLevel level) { FullToColumnTransformer.writeFullDataChunkToColumnData(this, level, chunkData); }
//=====================//
// data helper methods //
//=====================//
@Override
public boolean doesDataPointExist(int posX, int posZ) { return ColumnFormat.doesDataPointExist(this.getFirstDataPoint(posX, posZ)); }
@Override
public void generateData(IColumnDatatype lowerDataContainer, int posX, int posZ)
{
ColumnQuadView quadView = lowerDataContainer.getDataInQuad(posX * 2, posZ * 2, 2, 2);
ColumnArrayView outputView = getVerticalDataView(posX, posZ);
ColumnArrayView outputView = this.getVerticalDataPointView(posX, posZ);
ColumnQuadView quadView = lowerDataContainer.getQuadViewOverRange(posX * 2, posZ * 2, 2, 2);
outputView.mergeMultiDataFrom(quadView);
}
boolean writeData(DataOutputStream output) throws IOException
{
output.writeByte(getDataDetail());
output.writeByte((byte) verticalSize);
// FIXME: yOffset is a int, but we only are writing a short.
if (isEmpty)
{
output.writeByte(Short.MAX_VALUE & 0xFF);
output.writeByte((Short.MAX_VALUE >> 8) & 0xFF);
return false;
}
output.writeByte((byte) (yOffset & 0xFF));
output.writeByte((byte) ((yOffset >> 8) & 0xFF));
boolean allGenerated = true;
int x = SECTION_SIZE * SECTION_SIZE;
for (int i = 0; i < x; i++)
{
for (int j = 0; j < verticalSize; j++)
{
long current = dataContainer[i * verticalSize + j];
if (ColumnFormat.doesItExist(current))
current = ColumnFormat.overrideGenerationMode(current, (byte) 1);
output.writeLong(Long.reverseBytes(current));
}
if (!ColumnFormat.doesItExist(dataContainer[i]))
allGenerated = false;
}
return allGenerated;
}
public String toString()
{
String LINE_DELIMITER = "\n";
String DATA_DELIMITER = " ";
String SUBDATA_DELIMITER = ",";
StringBuilder stringBuilder = new StringBuilder();
int size = sectionPos.getWidth().value;
stringBuilder.append(sectionPos);
stringBuilder.append(LINE_DELIMITER);
for (int z = 0; z < size; z++)
{
for (int x = 0; x < size; x++)
{
for (int y = 0; y < verticalSize; y++)
{
//Converting the dataToHex
stringBuilder.append(Long.toHexString(getData(x, z, y)));
if (y != verticalSize - 1)
stringBuilder.append(SUBDATA_DELIMITER);
}
if (x != size - 1)
stringBuilder.append(DATA_DELIMITER);
}
if (z != size - 1)
stringBuilder.append(LINE_DELIMITER);
}
return stringBuilder.toString();
}
@Override
public int getMaxLodCount() { return SECTION_SIZE * SECTION_SIZE * getVerticalSize(); }
@Override
public int getMaxNumberOfLods() { return SECTION_SIZE * SECTION_SIZE * getVerticalSize(); }
public long getRoughRamUsageInBytes() { return (long) this.dataContainer.length * Long.BYTES; }
@Override
public long getRoughRamUsageInBytes() { return (long) dataContainer.length * Long.BYTES; }
public DhSectionPos getSectionPos() { return this.sectionPos; }
public DhSectionPos getSectionPos() { return sectionPos; }
public byte getDataDetail() { return (byte) (sectionPos.sectionDetail - SECTION_SIZE_OFFSET); }
public byte getDataDetail() { return (byte) (this.sectionPos.sectionDetail - SECTION_SIZE_OFFSET); }
@Override
public byte getDetailOffset() { return SECTION_SIZE_OFFSET; }
//================//
// Render Methods //
//================//
private void tryBuildBuffer(IDhClientLevel level, LodQuadTree quadTree)
{
if (inBuildRenderBuffer == null && !ColumnRenderBuffer.isBusy() && !isEmpty)
if (this.inBuildRenderBuffer == null && !ColumnRenderBuffer.isBusy() && !this.isEmpty)
{
ColumnRenderSource[] data = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length];
for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS)
{
LodRenderSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels
LodRenderSection section = quadTree.getSection(this.sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels
if (section != null && section.getRenderSource() != null && section.getRenderSource() instanceof ColumnRenderSource)
{
data[direction.ordinal() - 2] = ((ColumnRenderSource) section.getRenderSource());
}
}
inBuildRenderBuffer = ColumnRenderBuffer.build(level, usedBuffer, this, data);
this.inBuildRenderBuffer = ColumnRenderBuffer.build(level, this.usedBuffer, this, data);
}
}
private void cancelBuildBuffer()
{
if (inBuildRenderBuffer != null)
if (this.inBuildRenderBuffer != null)
{
//LOGGER.info("Cancelling build of render buffer for {}", sectionPos);
inBuildRenderBuffer.cancel(true);
inBuildRenderBuffer = null;
this.inBuildRenderBuffer.cancel(true);
this.inBuildRenderBuffer = null;
}
}
@@ -355,37 +410,40 @@ public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype
@Override
public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference<RenderBuffer> referenceSlot)
{
if (lastNs != -1 && System.nanoTime() - lastNs < SWAP_TIMEOUT)
if (this.lastNs != -1 && System.nanoTime() - this.lastNs < SWAP_TIMEOUT)
{
return false;
}
if (inBuildRenderBuffer != null)
if (this.inBuildRenderBuffer != null)
{
if (inBuildRenderBuffer.isDone())
if (this.inBuildRenderBuffer.isDone())
{
lastNs = System.nanoTime();
this.lastNs = System.nanoTime();
//LOGGER.info("Swapping render buffer for {}", sectionPos);
RenderBuffer newBuffer = inBuildRenderBuffer.join();
RenderBuffer newBuffer = this.inBuildRenderBuffer.join();
RenderBuffer oldBuffer = referenceSlot.getAndSet(newBuffer);
if (oldBuffer instanceof ColumnRenderBuffer)
{
ColumnRenderBuffer swapped = usedBuffer.swap((ColumnRenderBuffer) oldBuffer);
ColumnRenderBuffer swapped = this.usedBuffer.swap((ColumnRenderBuffer) oldBuffer);
LodUtil.assertTrue(swapped == null);
}
inBuildRenderBuffer = null;
this.inBuildRenderBuffer = null;
return true;
}
}
else
{
if (!isEmpty)
if (!this.isEmpty)
{
if (ColumnRenderBuffer.isBusy())
{
lastNs += (long) (SWAP_BUSY_COLLISION_TIMEOUT * Math.random());
this.lastNs += (long) (SWAP_BUSY_COLLISION_TIMEOUT * Math.random());
}
else
tryBuildBuffer(level, quadTree);
{
this.tryBuildBuffer(this.level, quadTree);
}
}
}
return false;
@@ -405,40 +463,68 @@ public class ColumnRenderSource implements ILodRenderSource, IColumnDatatype
public boolean isValid() { return true; }
@Override
public boolean isEmpty() { return isEmpty; }
public boolean isEmpty() { return this.isEmpty; }
public void markNotEmpty() { this.isEmpty = false; }
public void markNotEmpty() { isEmpty = false; }
@Override
public void weakWrite(ILodRenderSource source)
//=======//
// debug //
//=======//
/** Sets the debug flag for the given area */
public void fillDebugFlag(int startX, int startZ, int width, int height, DebugSourceFlag flag)
{
LodUtil.assertTrue(source instanceof ColumnRenderSource);
ColumnRenderSource src = (ColumnRenderSource) source;
LodUtil.assertTrue(src.sectionPos.equals(sectionPos));
LodUtil.assertTrue(src.verticalSize == verticalSize);
if (src.isEmpty)
return;
isEmpty = false;
for (int i = 0; i < dataContainer.length; i += verticalSize)
for (int x = startX; x < startX + width; x++)
{
int genMode = ColumnFormat.getGenerationMode(dataContainer[i]);
int srcGenMode = ColumnFormat.getGenerationMode(src.dataContainer[i]);
if (srcGenMode == 0)
continue;
if (genMode <= srcGenMode)
for (int z = startZ; z < startZ + height; z++)
{
new ColumnArrayView(dataContainer, verticalSize, i, verticalSize).copyFrom(
new ColumnArrayView(src.dataContainer, verticalSize, i, verticalSize));
debugSourceFlags[i / verticalSize] = src.debugSourceFlags[i / verticalSize];
debugSourceFlags[x * SECTION_SIZE + z] = flag;
}
}
}
public DebugSourceFlag debugGetFlag(int ox, int oz) { return debugSourceFlags[ox * SECTION_SIZE + oz]; }
//==============//
// base methods //
//==============//
@Override
public void fastWrite(ChunkSizedData chunkData, IDhClientLevel level) { FullToColumnTransformer.writeFullDataChunkToColumnData(this, level, chunkData); }
public String toString()
{
String LINE_DELIMITER = "\n";
String DATA_DELIMITER = " ";
String SUBDATA_DELIMITER = ",";
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(sectionPos);
stringBuilder.append(LINE_DELIMITER);
int size = sectionPos.getWidth().value;
for (int z = 0; z < size; z++)
{
for (int x = 0; x < size; x++)
{
for (int y = 0; y < verticalSize; y++)
{
//Converting the dataToHex
stringBuilder.append(Long.toHexString(getDataPoint(x, z, y)));
if (y != verticalSize - 1)
stringBuilder.append(SUBDATA_DELIMITER);
}
if (x != size - 1)
stringBuilder.append(DATA_DELIMITER);
}
if (z != size - 1)
stringBuilder.append(LINE_DELIMITER);
}
return stringBuilder.toString();
}
@@ -208,7 +208,7 @@ public class ColumnFormat {
public static byte getGenerationMode(long dataPoint) {
byte genMode = (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
if (warnLogger.canMaybeLog() && doesItExist(dataPoint) && genMode == 0) {
if (warnLogger.canMaybeLog() && doesDataPointExist(dataPoint) && genMode == 0) {
warnLogger.warnInc("Existing datapoint with genMode 0 detected! This is invalid in DataPoint version 10!"
+ " This may be caused by old data that has not been updated correctly.");
return 1;
@@ -224,7 +224,7 @@ public class ColumnFormat {
return (((dataPoint >>> DEPTH_SHIFT) & HEIGHT_DEPTH_MASK) == 0);
}
public static boolean doesItExist(long dataPoint) {
public static boolean doesDataPointExist(long dataPoint) {
return dataPoint != 0;
}
@@ -238,7 +238,7 @@ public class ColumnFormat {
*/
@SuppressWarnings("unused")
public static String toString(long dataPoint) {
if (!doesItExist(dataPoint)) return "null";
if (!doesDataPointExist(dataPoint)) return "null";
if (isVoid(dataPoint)) return "void";
return "H:" + getHeight(dataPoint) +
" D:" + getDepth(dataPoint) +
@@ -347,7 +347,7 @@ public class ColumnFormat {
for (int index = 0; index < dataCount; index++) {
tempData = sourceData.get(index * inputVerticalSize);
allVoid = allVoid && ColumnFormat.isVoid(tempData);
allEmpty = allEmpty && !ColumnFormat.doesItExist(tempData);
allEmpty = allEmpty && !ColumnFormat.doesDataPointExist(tempData);
}
//We check if there is any data that's not empty or void
@@ -375,7 +375,7 @@ public class ColumnFormat {
for (int index = 0; index < dataCount; index++) {
if (indeces[index] < inputVerticalSize) {
tempData = sourceData.get(index * inputVerticalSize + indeces[index]);
if (!ColumnFormat.isVoid(tempData) && ColumnFormat.doesItExist(tempData)) {
if (!ColumnFormat.isVoid(tempData) && ColumnFormat.doesDataPointExist(tempData)) {
tempHeight = ColumnFormat.getHeight(tempData);
tempDepth = ColumnFormat.getDepth(tempData);
if (tempDepth >= newHeight) {
@@ -452,7 +452,7 @@ public class ColumnFormat {
for (int index = 0; index < dataCount; index++) {
if (indeces[index] < inputVerticalSize) {
tempData = sourceData.get(index * inputVerticalSize + indeces[index]);
stillHasDataToCheck |= !ColumnFormat.isVoid(tempData) && ColumnFormat.doesItExist(tempData);
stillHasDataToCheck |= !ColumnFormat.isVoid(tempData) && ColumnFormat.doesDataPointExist(tempData);
}
}
}
@@ -522,7 +522,7 @@ public class ColumnFormat {
//we scan the lods in the position from top to bottom
while (dataIndexesCache[index] < inputVerticalSize) {
singleData = sourceData.get(index * inputVerticalSize + dataIndexesCache[index]);
if (doesItExist(singleData) && !isVoid(singleData)) {
if (doesDataPointExist(singleData) && !isVoid(singleData)) {
dataIndexesCache[index]++;
if ((depth <= getDepth(singleData) && getDepth(singleData) < height)
|| (depth < getHeight(singleData) && getHeight(singleData) <= height)) {
@@ -532,11 +532,11 @@ public class ColumnFormat {
} else
break;
}
if (!doesItExist(data)) {
if (!doesDataPointExist(data)) {
data = createVoidDataPoint(genMode);
}
if (doesItExist(data)) {
if (doesDataPointExist(data)) {
allEmpty = false;
if (!isVoid(data)) {
numberOfChildren++;
@@ -9,37 +9,48 @@ public interface IColumnDatatype
return 1 << getDetailOffset();
}
int getMaxNumberOfLods();
/** Returns how many LODs could be contained by this object. */
int getMaxLodCount();
long getRoughRamUsageInBytes();
int getVerticalSize();
boolean doesItExist(int posX, int posZ);
boolean doesDataPointExist(int posX, int posZ);
long getData(int posX, int posZ, int verticalIndex);
/** Returns the datapoint for the given relative coordinates and vertical index */
long getDataPoint(int posX, int posZ, int verticalIndex);
/**
* Returns the top datapoint for the given relative coordinates <br>
* Returns the empty datapoint if no data is present.
*/
default long getFirstDataPoint(int posX, int posZ) { return getDataPoint(posX, posZ, 0); }
default long getSingleData(int posX, int posZ) { return getData(posX, posZ, 0); }
/** Returns every datapoint in the vertical slice at the given position as an array */
long[] getVerticalDataPointArray(int posX, int posZ);
/** Returns every datapoint in the vertical slice at the given position as a ColumnArrayView */
ColumnArrayView getVerticalDataPointView(int posX, int posZ);
long[] getAllData(int posX, int posZ);
/** Returns a QuadView that covers this whole object */
ColumnQuadView getFullQuadView();
/** Returns a QuadView over the give coordinate range */
ColumnQuadView getQuadViewOverRange(int quadX, int quadZ, int quadXSize, int quadZSize);
ColumnArrayView getVerticalDataView(int posX, int posZ);
/** clears the datapoint stored at the relative position */
void clearDataPoint(int posX, int posZ);
ColumnQuadView getDataInQuad(int quadX, int quadZ, int quadXSize, int quadZSize);
ColumnQuadView getFullQuad();
/** clears all data at the relative position */
void clear(int posX, int posZ);
/** adds the given data to the relative position and vertical index */
boolean addData(long data, int posX, int posZ, int verticalIndex);
/**
* adds/sets the given datapoint at the relative position and vertical index
* @return true if the datapoint was added/set
*/
boolean setDataPoint(long data, int posX, int posZ, int verticalIndex);
/**
* This methods will add the data in the given position if certain condition are satisfied
* @param override if override is true we can override data created with same generation mode
* @param overwriteDataWithSameGenerationMode if false old data will only be overwritten if it was generated with a lower priority than the newData
* @return true if the newData was successfully added, false otherwise
*/
boolean copyVerticalData(IColumnDataView data, int posX, int posZ, boolean override);
boolean copyVerticalData(IColumnDataView newData, int posX, int posZ, boolean overwriteDataWithSameGenerationMode);
void generateData(IColumnDatatype lowerDataContainer, int posX, int posZ);
@@ -25,7 +25,6 @@ import com.seibel.lod.core.render.renderer.LodRenderer;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.MathUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -40,7 +39,7 @@ public class ColumnBox
short maxY = (short) (y + ySize);
short maxZ = (short) (z + zSize);
byte skyLightTop = skyLight;
byte skyLightBot = ColumnFormat.doesItExist(botData) ? ColumnFormat.getLightSky(botData) : 0;
byte skyLightBot = ColumnFormat.doesDataPointExist(botData) ? ColumnFormat.getLightSky(botData) : 0;
boolean isTransparent = ColorUtil.getAlpha(color)<255 && LodRenderer.transparencyEnabled;
boolean isTopTransparent = ColumnFormat.getAlpha(topData)<255 && LodRenderer.transparencyEnabled;
@@ -51,15 +50,15 @@ public class ColumnBox
//We skip if
// current block is not transparent: we check if the adj block is attached and opaque
boolean skipTop = ColumnFormat.doesItExist(topData) && (ColumnFormat.getDepth(topData) == maxY) && !isTopTransparent;
boolean skipBot = ColumnFormat.doesItExist(botData) && (ColumnFormat.getHeight(botData) == y) && !isBotTransparent;
boolean skipTop = ColumnFormat.doesDataPointExist(topData) && (ColumnFormat.getDepth(topData) == maxY) && !isTopTransparent;
boolean skipBot = ColumnFormat.doesDataPointExist(botData) && (ColumnFormat.getHeight(botData) == y) && !isBotTransparent;
if(LodRenderer.transparencyEnabled && LodRenderer.fakeOceanFloor) {
if (!isTransparent && isTopTransparent && ColumnFormat.doesItExist(topData)) {
if (!isTransparent && isTopTransparent && ColumnFormat.doesDataPointExist(topData)) {
skyLightTop = (byte) MathUtil.clamp(0, 15 - (ColumnFormat.getHeight(topData) - y), 15);
ySize = (short) (ColumnFormat.getHeight(topData) - y - 1);
//y = (short) (DataPointUtil.getHeight(topData) - 2);
//ySize = 1;
} else if (isTransparent && !isBotTransparent && ColumnFormat.doesItExist(botData)) {
} else if (isTransparent && !isBotTransparent && ColumnFormat.doesDataPointExist(botData)) {
y = (short) (y + ySize - 1);
ySize = 1;
}
@@ -183,7 +182,7 @@ public class ColumnBox
byte nextSkyLight = upSkyLight;
boolean isTransparent = ColorUtil.getAlpha(color) < 255 && LodRenderer.transparencyEnabled;
boolean lastWasTransparent = false;
for (i = 0; i < dataPoint.size() && ColumnFormat.doesItExist(adjData.get(i))
for (i = 0; i < dataPoint.size() && ColumnFormat.doesDataPointExist(adjData.get(i))
&& !ColumnFormat.isVoid(adjData.get(i)); i++)
{
long adjPoint = adjData.get(i);
@@ -328,7 +327,7 @@ public class ColumnBox
previousDepth = depth;
firstFace = false;
nextSkyLight = upSkyLight;
if (i + 1 < adjData.size() && ColumnFormat.doesItExist(adjData.get(i + 1)))
if (i + 1 < adjData.size() && ColumnFormat.doesDataPointExist(adjData.get(i + 1)))
nextSkyLight = ColumnFormat.getLightSky(adjData.get(i + 1));
lastWasTransparent = isAdjTransparent;
}
@@ -298,8 +298,8 @@ public class ColumnRenderBuffer extends RenderBuffer {
for (int z = 0; z < ColumnRenderSource.SECTION_SIZE; z++) {
UncheckedInterruptedException.throwIfInterrupted();
ColumnArrayView posData = region.getVerticalDataView(x, z);
if (posData.size() == 0 || !ColumnFormat.doesItExist(posData.get(0))
ColumnArrayView posData = region.getVerticalDataPointView(x, z);
if (posData.size() == 0 || !ColumnFormat.doesDataPointExist(posData.get(0))
|| ColumnFormat.isVoid(posData.get(0)))
continue;
ColumnRenderSource.DebugSourceFlag debugSourceFlag = region.debugGetFlag(x, z);
@@ -355,11 +355,11 @@ public class ColumnRenderBuffer extends RenderBuffer {
if (adjDetail == detailLevel || adjDetail > detailLevel) {
adjData[lodDirection.ordinal() - 2] = new ColumnArrayView[1];
adjData[lodDirection.ordinal() - 2][0] = adjRegion.getVerticalDataView(xAdj, zAdj);
adjData[lodDirection.ordinal() - 2][0] = adjRegion.getVerticalDataPointView(xAdj, zAdj);
} else {
adjData[lodDirection.ordinal() - 2] = new ColumnArrayView[2];
adjData[lodDirection.ordinal() - 2][0] = adjRegion.getVerticalDataView(xAdj, zAdj);
adjData[lodDirection.ordinal() - 2][1] = adjRegion.getVerticalDataView(
adjData[lodDirection.ordinal() - 2][0] = adjRegion.getVerticalDataPointView(xAdj, zAdj);
adjData[lodDirection.ordinal() - 2][1] = adjRegion.getVerticalDataPointView(
xAdj + (lodDirection.getAxis()== ELodDirection.Axis.X ? 0 : 1),
zAdj + (lodDirection.getAxis()== ELodDirection.Axis.Z ? 0 : 1));
}
@@ -375,7 +375,7 @@ public class ColumnRenderBuffer extends RenderBuffer {
long data = posData.get(i);
// If the data is not renderable (Void or non-existing) we stop since there is
// no data left in this position
if (ColumnFormat.isVoid(data) || !ColumnFormat.doesItExist(data))
if (ColumnFormat.isVoid(data) || !ColumnFormat.doesDataPointExist(data))
break;
long adjDataTop = i - 1 >= 0 ? posData.get(i - 1) : ColumnFormat.EMPTY_DATA;
@@ -40,13 +40,13 @@ public class FullToColumnTransformer {
int baseZ = pos.getCorner().getCorner().z;
for (int x = 0; x < pos.getWidth(dataDetail).value; x++) {
for (int z = 0; z < pos.getWidth(dataDetail).value; z++) {
ColumnArrayView columnArrayView = columnSource.getVerticalDataView(x, z);
ColumnArrayView columnArrayView = columnSource.getVerticalDataPointView(x, z);
SingleFullArrayView fullArrayView = data.get(x, z);
convertColumnData(level, baseX + x, baseZ + z, columnArrayView, fullArrayView, 1);
if (fullArrayView.doesItExist()) LodUtil.assertTrue(columnSource.doesItExist(x, z));
if (fullArrayView.doesItExist()) LodUtil.assertTrue(columnSource.doesDataPointExist(x, z));
}
}
columnSource.debugFillFlag(0, 0, ColumnRenderSource.SECTION_SIZE, ColumnRenderSource.SECTION_SIZE, ColumnRenderSource.DebugSourceFlag.FULL);
columnSource.fillDebugFlag(0, 0, ColumnRenderSource.SECTION_SIZE, ColumnRenderSource.SECTION_SIZE, ColumnRenderSource.DebugSourceFlag.FULL);
// } else if (dataDetail == 0 && columnSource.getDataDetail() > dataDetail) {
// byte deltaDetail = (byte) (columnSource.getDataDetail() - dataDetail);
// int perColumnWidth = 1 << deltaDetail;
@@ -82,10 +82,10 @@ public class FullToColumnTransformer {
for (int z = 0; z < pos.getWidth(dataDetail).value; z++) {
SingleFullArrayView fullArrayView = data.tryGet(x, z);
if (fullArrayView == null) continue;
ColumnArrayView columnArrayView = columnSource.getVerticalDataView(x, z);
ColumnArrayView columnArrayView = columnSource.getVerticalDataPointView(x, z);
convertColumnData(level, baseX + x, baseZ + z, columnArrayView, fullArrayView, 1);
columnSource.debugFillFlag(x, z, 1, 1, ColumnRenderSource.DebugSourceFlag.SPARSE);
if (fullArrayView.doesItExist()) LodUtil.assertTrue(columnSource.doesItExist(x, z));
columnSource.fillDebugFlag(x, z, 1, 1, ColumnRenderSource.DebugSourceFlag.SPARSE);
if (fullArrayView.doesItExist()) LodUtil.assertTrue(columnSource.doesDataPointExist(x, z));
}
}
} else {
@@ -112,15 +112,15 @@ public class FullToColumnTransformer {
throw new IllegalArgumentException("Data offset is out of bounds");
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
ColumnArrayView columnArrayView = render.getVerticalDataView(renderOffsetX + x, renderOffsetZ + z);
ColumnArrayView columnArrayView = render.getVerticalDataPointView(renderOffsetX + x, renderOffsetZ + z);
SingleFullArrayView fullArrayView = data.get(x, z);
convertColumnData(level, blockX + perRenderWidth * (renderOffsetX+x),
blockZ + perRenderWidth * (renderOffsetZ+z),
columnArrayView, fullArrayView, 2);
if (fullArrayView.doesItExist()) LodUtil.assertTrue(render.doesItExist(renderOffsetX + x, renderOffsetZ + z));
if (fullArrayView.doesItExist()) LodUtil.assertTrue(render.doesDataPointExist(renderOffsetX + x, renderOffsetZ + z));
}
}
render.debugFillFlag(renderOffsetX, renderOffsetZ, 16, 16, ColumnRenderSource.DebugSourceFlag.DIRECT);
render.fillDebugFlag(renderOffsetX, renderOffsetZ, 16, 16, ColumnRenderSource.DebugSourceFlag.DIRECT);
} else {
final int dataPerRender = 1 << (render.getDataDetail() - data.dataDetail);
final int dataSize = 16 / dataPerRender;
@@ -141,11 +141,11 @@ public class FullToColumnTransformer {
columnArrayView, fullArrayView, 2);
}
}
ColumnArrayView downSampledArrayView = render.getVerticalDataView(renderOffsetX + x, renderOffsetZ + z);
ColumnArrayView downSampledArrayView = render.getVerticalDataPointView(renderOffsetX + x, renderOffsetZ + z);
downSampledArrayView.mergeMultiDataFrom(tempQuadView);
}
}
render.debugFillFlag(renderOffsetX, renderOffsetZ, dataSize, dataSize, ColumnRenderSource.DebugSourceFlag.DIRECT);
render.fillDebugFlag(renderOffsetX, renderOffsetZ, dataSize, dataSize, ColumnRenderSource.DebugSourceFlag.DIRECT);
}
}
@@ -17,7 +17,6 @@ import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.util.LodUtil;
import org.apache.logging.log4j.Logger;
import org.lwjgl.system.CallbackI;
import java.io.File;
import java.io.IOException;
@@ -241,7 +240,7 @@ public class RenderFileHandler implements IRenderSourceProvider {
ILodRenderSource newData, long newDataVersion) {
if (target == null) return;
if (newData == null) return;
target.weakWrite(newData);
target.updateFromRenderSource(newData);
file.metaData.dataVersion.set(newDataVersion);
file.metaData.dataLevel = target.getDataDetail();
file.loader = AbstractRenderSourceLoader.getLoader(target.getClass(), target.getRenderVersion());