Nuke no longer used files and fix bugs where I'm using the wrong class for doing data formats

This commit is contained in:
TomTheFurry
2022-09-12 22:13:20 +08:00
parent f2c19ef3a3
commit dfc75f2a65
52 changed files with 78 additions and 3763 deletions
@@ -85,16 +85,7 @@ public class DhApiGraphics
/** Modifies the quadratic function fake chunks use for horizontal quality drop-off. */ /** Modifies the quadratic function fake chunks use for horizontal quality drop-off. */
public static IDhApiConfig<EDhApiHorizontalQuality> getHorizontalQualityDropoffConfig() public static IDhApiConfig<EDhApiHorizontalQuality> getHorizontalQualityDropoffConfig()
{ return new DhApiConfig<EHorizontalQuality, EDhApiHorizontalQuality>(Quality.horizontalQuality, new GenericEnumConverter<>(EHorizontalQuality.class, EDhApiHorizontalQuality.class)); } { return new DhApiConfig<EHorizontalQuality, EDhApiHorizontalQuality>(Quality.horizontalQuality, new GenericEnumConverter<>(EHorizontalQuality.class, EDhApiHorizontalQuality.class)); }
/**
* Defines how fake chunks drop off in quality. <br><br>
*
* Higher quality settings require fake chunk geometry data to be
* rebuilt more often when moving but make quality drop-off less noticeable.
* */
public static IDhApiConfig<EDhApiDropoffQuality> getHorizontalQualityDropoffMethodConfig()
{ return new DhApiConfig<EDropoffQuality, EDhApiDropoffQuality>(Quality.dropoffQuality, new GenericEnumConverter<>(EDropoffQuality.class, EDhApiDropoffQuality.class)); }
/** /**
* The same as vanilla Minecraft's biome blending. <br><br> * The same as vanilla Minecraft's biome blending. <br><br>
* *
@@ -12,7 +12,7 @@ import com.seibel.lod.core.util.*;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
//FIXME: Unused class??? //FIXME: To-Be-Used class
public class LodBuilder { public class LodBuilder {
public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(), public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
() -> Config.Client.Advanced.Debugging.DebugSwitch.logLodBuilderEvent.get()); () -> Config.Client.Advanced.Debugging.DebugSwitch.logLodBuilderEvent.get());
@@ -76,5 +76,5 @@ public class LodBuilder {
else // Else, it means someone managed to sneak in a new gen request in this pos. Then lets drop this old task. else // Else, it means someone managed to sneak in a new gen request in this pos. Then lets drop this old task.
task.future.complete(null); task.future.complete(null);
} }
} }
@@ -4,10 +4,7 @@ import com.seibel.lod.core.a7.datatype.full.ChunkSizedData;
import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.level.ILevel;
import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.save.io.file.DataMetaFile; import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
import com.seibel.lod.core.a7.util.IOUtil;
import com.seibel.lod.core.objects.DHChunkPos;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@@ -1,9 +1,6 @@
package com.seibel.lod.core.a7.datatype.column; package com.seibel.lod.core.a7.datatype.column;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView; import com.seibel.lod.core.a7.datatype.column.accessor.*;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnFormat;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnQuadView;
import com.seibel.lod.core.a7.datatype.column.accessor.IColumnDatatype;
import com.seibel.lod.core.a7.datatype.column.render.ColumnRenderBuffer; import com.seibel.lod.core.a7.datatype.column.render.ColumnRenderBuffer;
import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; import com.seibel.lod.core.a7.datatype.full.ChunkSizedData;
import com.seibel.lod.core.a7.datatype.transform.FullToColumnTransformer; import com.seibel.lod.core.a7.datatype.transform.FullToColumnTransformer;
@@ -14,7 +11,6 @@ import com.seibel.lod.core.a7.render.a7LodRenderer;
import com.seibel.lod.core.a7.save.io.render.RenderMetaFile; import com.seibel.lod.core.a7.save.io.render.RenderMetaFile;
import com.seibel.lod.core.enums.ELodDirection; import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.objects.LodDataView;
import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.level.ILevel;
import com.seibel.lod.core.a7.render.LodQuadTree; import com.seibel.lod.core.a7.render.LodQuadTree;
import com.seibel.lod.core.a7.render.LodRenderSection; import com.seibel.lod.core.a7.render.LodRenderSection;
@@ -121,7 +117,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
} }
@Override @Override
public boolean copyVerticalData(LodDataView data, int posX, int posZ, boolean override) { public boolean copyVerticalData(IColumnDataView data, int posX, int posZ, boolean override) {
if (DO_SAFETY_CHECKS) { if (DO_SAFETY_CHECKS) {
if (data.size() != verticalSize) if (data.size() != verticalSize)
throw new IllegalArgumentException("data size not the same as vertical size"); throw new IllegalArgumentException("data size not the same as vertical size");
@@ -137,7 +133,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype {
} else { } else {
if (compare<=0) return false; if (compare<=0) return false;
} }
data.copyTo(dataContainer, index); data.copyTo(dataContainer, index, data.size());
return true; return true;
} }
@@ -19,11 +19,8 @@
package com.seibel.lod.core.a7.datatype.column.accessor; package com.seibel.lod.core.a7.datatype.column.accessor;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
import com.seibel.lod.core.a7.datatype.column.accessor.IColumnDataView;
import com.seibel.lod.core.logging.SpamReducedLogger; import com.seibel.lod.core.logging.SpamReducedLogger;
import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.LodUtil;
import java.util.Arrays; import java.util.Arrays;
@@ -349,8 +346,8 @@ public class ColumnFormat {
long tempData; long tempData;
for (int index = 0; index < dataCount; index++) { for (int index = 0; index < dataCount; index++) {
tempData = sourceData.get(index * inputVerticalSize); tempData = sourceData.get(index * inputVerticalSize);
allVoid = allVoid && DataPointUtil.isVoid(tempData); allVoid = allVoid && ColumnFormat.isVoid(tempData);
allEmpty = allEmpty && !DataPointUtil.doesItExist(tempData); allEmpty = allEmpty && !ColumnFormat.doesItExist(tempData);
} }
//We check if there is any data that's not empty or void //We check if there is any data that's not empty or void
@@ -378,9 +375,9 @@ public class ColumnFormat {
for (int index = 0; index < dataCount; index++) { for (int index = 0; index < dataCount; index++) {
if (indeces[index] < inputVerticalSize) { if (indeces[index] < inputVerticalSize) {
tempData = sourceData.get(index * inputVerticalSize + indeces[index]); tempData = sourceData.get(index * inputVerticalSize + indeces[index]);
if (!DataPointUtil.isVoid(tempData) && DataPointUtil.doesItExist(tempData)) { if (!ColumnFormat.isVoid(tempData) && ColumnFormat.doesItExist(tempData)) {
tempHeight = DataPointUtil.getHeight(tempData); tempHeight = ColumnFormat.getHeight(tempData);
tempDepth = DataPointUtil.getDepth(tempData); tempDepth = ColumnFormat.getDepth(tempData);
if (tempDepth >= newHeight) { if (tempDepth >= newHeight) {
//First case //First case
//the column we are checking is higher than the current column //the column we are checking is higher than the current column
@@ -455,7 +452,7 @@ public class ColumnFormat {
for (int index = 0; index < dataCount; index++) { for (int index = 0; index < dataCount; index++) {
if (indeces[index] < inputVerticalSize) { if (indeces[index] < inputVerticalSize) {
tempData = sourceData.get(index * inputVerticalSize + indeces[index]); tempData = sourceData.get(index * inputVerticalSize + indeces[index]);
stillHasDataToCheck |= !DataPointUtil.isVoid(tempData) && DataPointUtil.doesItExist(tempData); stillHasDataToCheck |= !ColumnFormat.isVoid(tempData) && ColumnFormat.doesItExist(tempData);
} }
} }
} }
@@ -1,7 +1,5 @@
package com.seibel.lod.core.a7.datatype.column.accessor; package com.seibel.lod.core.a7.datatype.column.accessor;
import com.seibel.lod.core.objects.LodDataView;
public interface IColumnDatatype { public interface IColumnDatatype {
byte getDetailOffset(); byte getDetailOffset();
default int getDataSize() { default int getDataSize() {
@@ -31,6 +29,6 @@ public interface IColumnDatatype {
* This methods will add the data in the given position if certain condition are satisfied * 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 override if override is true we can override data created with same generation mode
*/ */
boolean copyVerticalData(LodDataView data, int posX, int posZ, boolean override); boolean copyVerticalData(IColumnDataView data, int posX, int posZ, boolean override);
void generateData(IColumnDatatype lowerDataContainer, int posX, int posZ); void generateData(IColumnDatatype lowerDataContainer, int posX, int posZ);
} }
@@ -20,13 +20,12 @@
package com.seibel.lod.core.a7.datatype.column.render; package com.seibel.lod.core.a7.datatype.column.render;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView; import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnFormat;
import com.seibel.lod.core.a7.render.a7LodRenderer; import com.seibel.lod.core.a7.render.a7LodRenderer;
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder; import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.enums.ELodDirection; import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -41,26 +40,26 @@ public class ColumnBox
short maxY = (short) (y + ySize); short maxY = (short) (y + ySize);
short maxZ = (short) (z + zSize); short maxZ = (short) (z + zSize);
byte skyLightTop = skyLight; byte skyLightTop = skyLight;
byte skyLightBot = DataPointUtil.doesItExist(botData) ? DataPointUtil.getLightSky(botData) : 0; byte skyLightBot = ColumnFormat.doesItExist(botData) ? ColumnFormat.getLightSky(botData) : 0;
boolean isTransparent = ColorUtil.getAlpha(color)<255 && a7LodRenderer.transparencyEnabled; boolean isTransparent = ColorUtil.getAlpha(color)<255 && a7LodRenderer.transparencyEnabled;
boolean isTopTransparent = DataPointUtil.getAlpha(topData)<255 && a7LodRenderer.transparencyEnabled; boolean isTopTransparent = ColumnFormat.getAlpha(topData)<255 && a7LodRenderer.transparencyEnabled;
boolean isBotTransparent = DataPointUtil.getAlpha(botData)<255 && a7LodRenderer.transparencyEnabled; boolean isBotTransparent = ColumnFormat.getAlpha(botData)<255 && a7LodRenderer.transparencyEnabled;
// Up direction case // Up direction case
//We skip if //We skip if
// current block is not transparent: we check if the adj block is attached and opaque // current block is not transparent: we check if the adj block is attached and opaque
boolean skipTop = DataPointUtil.doesItExist(topData) && (DataPointUtil.getDepth(topData) == maxY) && !isTopTransparent; boolean skipTop = ColumnFormat.doesItExist(topData) && (ColumnFormat.getDepth(topData) == maxY) && !isTopTransparent;
boolean skipBot = DataPointUtil.doesItExist(botData) && (DataPointUtil.getHeight(botData) == y) && !isBotTransparent; boolean skipBot = ColumnFormat.doesItExist(botData) && (ColumnFormat.getHeight(botData) == y) && !isBotTransparent;
if(a7LodRenderer.transparencyEnabled && a7LodRenderer.fakeOceanFloor) { if(a7LodRenderer.transparencyEnabled && a7LodRenderer.fakeOceanFloor) {
if (!isTransparent && isTopTransparent && DataPointUtil.doesItExist(topData)) { if (!isTransparent && isTopTransparent && ColumnFormat.doesItExist(topData)) {
skyLightTop = (byte) LodUtil.clamp(0, 15 - (DataPointUtil.getHeight(topData) - y), 15); skyLightTop = (byte) LodUtil.clamp(0, 15 - (ColumnFormat.getHeight(topData) - y), 15);
ySize = (short) (DataPointUtil.getHeight(topData) - y - 1); ySize = (short) (ColumnFormat.getHeight(topData) - y - 1);
//y = (short) (DataPointUtil.getHeight(topData) - 2); //y = (short) (DataPointUtil.getHeight(topData) - 2);
//ySize = 1; //ySize = 1;
} else if (isTransparent && !isBotTransparent && DataPointUtil.doesItExist(botData)) { } else if (isTransparent && !isBotTransparent && ColumnFormat.doesItExist(botData)) {
y = (short) (y + ySize - 1); y = (short) (y + ySize - 1);
ySize = 1; ySize = 1;
} }
@@ -171,7 +170,7 @@ public class ColumnBox
{ {
color = ColorUtil.applyShade(color, MC.getShade(direction)); color = ColorUtil.applyShade(color, MC.getShade(direction));
ColumnArrayView dataPoint = adjData; ColumnArrayView dataPoint = adjData;
if (dataPoint == null || DataPointUtil.isVoid(dataPoint.get(0))) if (dataPoint == null || ColumnFormat.isVoid(dataPoint.get(0)))
{ {
builder.addQuadAdj(direction, x, y, z, w0, wy, color, (byte) 15, blockLight); builder.addQuadAdj(direction, x, y, z, w0, wy, color, (byte) 15, blockLight);
return; return;
@@ -184,30 +183,30 @@ public class ColumnBox
byte nextSkyLight = upSkyLight; byte nextSkyLight = upSkyLight;
boolean isTransparent = ColorUtil.getAlpha(color) < 255 && a7LodRenderer.transparencyEnabled; boolean isTransparent = ColorUtil.getAlpha(color) < 255 && a7LodRenderer.transparencyEnabled;
boolean lastWasTransparent = false; boolean lastWasTransparent = false;
for (i = 0; i < dataPoint.size() && DataPointUtil.doesItExist(adjData.get(i)) for (i = 0; i < dataPoint.size() && ColumnFormat.doesItExist(adjData.get(i))
&& !DataPointUtil.isVoid(adjData.get(i)); i++) && !ColumnFormat.isVoid(adjData.get(i)); i++)
{ {
long adjPoint = adjData.get(i); long adjPoint = adjData.get(i);
boolean isAdjTransparent = DataPointUtil.getAlpha(adjPoint) < 255 && a7LodRenderer.transparencyEnabled; boolean isAdjTransparent = ColumnFormat.getAlpha(adjPoint) < 255 && a7LodRenderer.transparencyEnabled;
if (!isTransparent && isAdjTransparent && a7LodRenderer.transparencyEnabled) if (!isTransparent && isAdjTransparent && a7LodRenderer.transparencyEnabled)
continue; continue;
short height = DataPointUtil.getHeight(adjPoint); short height = ColumnFormat.getHeight(adjPoint);
short depth = DataPointUtil.getDepth(adjPoint); short depth = ColumnFormat.getDepth(adjPoint);
if(a7LodRenderer.transparencyEnabled && a7LodRenderer.fakeOceanFloor) if(a7LodRenderer.transparencyEnabled && a7LodRenderer.fakeOceanFloor)
{ {
if(lastWasTransparent && !isAdjTransparent) if(lastWasTransparent && !isAdjTransparent)
{ {
height = (short) (DataPointUtil.getHeight(adjData.get(i-1)) - 1); height = (short) (ColumnFormat.getHeight(adjData.get(i-1)) - 1);
} }
else if(isAdjTransparent && (i + 1) < adjData.size()) else if(isAdjTransparent && (i + 1) < adjData.size())
{ {
if (DataPointUtil.getAlpha(adjData.get(i+1)) == 255) if (ColumnFormat.getAlpha(adjData.get(i+1)) == 255)
{ {
depth = (short) (height - 1); depth = (short) (height - 1);
} }
@@ -228,7 +227,7 @@ public class ColumnBox
// _______&&: depth ______ < y < maxY // _______&&: depth ______ < y < maxY
if (firstFace) if (firstFace)
{ {
builder.addQuadAdj(direction, x, y, z, w0, wy, color, DataPointUtil.getLightSky(adjPoint), builder.addQuadAdj(direction, x, y, z, w0, wy, color, ColumnFormat.getLightSky(adjPoint),
blockLight); blockLight);
} }
else else
@@ -237,7 +236,7 @@ public class ColumnBox
if (previousDepth == -1) if (previousDepth == -1)
throw new RuntimeException("Loop error"); throw new RuntimeException("Loop error");
builder.addQuadAdj(direction, x, y, z, w0, (short) (previousDepth - y), color, builder.addQuadAdj(direction, x, y, z, w0, (short) (previousDepth - y), color,
DataPointUtil.getLightSky(adjPoint), blockLight); ColumnFormat.getLightSky(adjPoint), blockLight);
previousDepth = -1; previousDepth = -1;
} }
break; break;
@@ -268,7 +267,7 @@ public class ColumnBox
if (firstFace) if (firstFace)
{ {
builder.addQuadAdj(direction, x, height, z, w0, (short) (y + wy - height), color, builder.addQuadAdj(direction, x, height, z, w0, (short) (y + wy - height), color,
DataPointUtil.getLightSky(adjPoint), blockLight); ColumnFormat.getLightSky(adjPoint), blockLight);
} }
else else
{ {
@@ -278,7 +277,7 @@ public class ColumnBox
if (previousDepth > height) if (previousDepth > height)
{ {
builder.addQuadAdj(direction, x, height, z, w0, (short) (previousDepth - height), color, builder.addQuadAdj(direction, x, height, z, w0, (short) (previousDepth - height), color,
DataPointUtil.getLightSky(adjPoint), blockLight); ColumnFormat.getLightSky(adjPoint), blockLight);
} }
previousDepth = -1; previousDepth = -1;
} }
@@ -310,7 +309,7 @@ public class ColumnBox
if (firstFace) if (firstFace)
{ {
builder.addQuadAdj(direction, x, height, z, w0, (short) (y + wy - height), color, builder.addQuadAdj(direction, x, height, z, w0, (short) (y + wy - height), color,
DataPointUtil.getLightSky(adjPoint), blockLight); ColumnFormat.getLightSky(adjPoint), blockLight);
} }
else else
{ {
@@ -320,7 +319,7 @@ public class ColumnBox
if (previousDepth > height) if (previousDepth > height)
{ {
builder.addQuadAdj(direction, x, height, z, w0, (short) (previousDepth - height), color, builder.addQuadAdj(direction, x, height, z, w0, (short) (previousDepth - height), color,
DataPointUtil.getLightSky(adjPoint), blockLight); ColumnFormat.getLightSky(adjPoint), blockLight);
} }
previousDepth = -1; previousDepth = -1;
} }
@@ -329,8 +328,8 @@ public class ColumnBox
previousDepth = depth; previousDepth = depth;
firstFace = false; firstFace = false;
nextSkyLight = upSkyLight; nextSkyLight = upSkyLight;
if (i + 1 < adjData.size() && DataPointUtil.doesItExist(adjData.get(i + 1))) if (i + 1 < adjData.size() && ColumnFormat.doesItExist(adjData.get(i + 1)))
nextSkyLight = DataPointUtil.getLightSky(adjData.get(i + 1)); nextSkyLight = ColumnFormat.getLightSky(adjData.get(i + 1));
lastWasTransparent = isAdjTransparent; lastWasTransparent = isAdjTransparent;
} }
@@ -2,6 +2,7 @@ package com.seibel.lod.core.a7.datatype.column.render;
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource; import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView; import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnFormat;
import com.seibel.lod.core.a7.level.IClientLevel; import com.seibel.lod.core.a7.level.IClientLevel;
import com.seibel.lod.core.a7.render.a7LodRenderer; import com.seibel.lod.core.a7.render.a7LodRenderer;
import com.seibel.lod.core.a7.util.UncheckedInterruptedException; import com.seibel.lod.core.a7.util.UncheckedInterruptedException;
@@ -290,8 +291,8 @@ public class ColumnRenderBuffer extends RenderBuffer {
UncheckedInterruptedException.throwIfInterrupted(); UncheckedInterruptedException.throwIfInterrupted();
ColumnArrayView posData = region.getVerticalDataView(x, z); ColumnArrayView posData = region.getVerticalDataView(x, z);
if (posData.size() == 0 || !DataPointUtil.doesItExist(posData.get(0)) if (posData.size() == 0 || !ColumnFormat.doesItExist(posData.get(0))
|| DataPointUtil.isVoid(posData.get(0))) || ColumnFormat.isVoid(posData.get(0)))
continue; continue;
ColumnArrayView[][] adjData = new ColumnArrayView[4][]; ColumnArrayView[][] adjData = new ColumnArrayView[4][];
@@ -365,15 +366,15 @@ public class ColumnRenderBuffer extends RenderBuffer {
long data = posData.get(i); long data = posData.get(i);
// If the data is not renderable (Void or non-existing) we stop since there is // If the data is not renderable (Void or non-existing) we stop since there is
// no data left in this position // no data left in this position
if (DataPointUtil.isVoid(data) || !DataPointUtil.doesItExist(data)) if (ColumnFormat.isVoid(data) || !ColumnFormat.doesItExist(data))
break; break;
long adjDataTop = i - 1 >= 0 ? posData.get(i - 1) : DataPointUtil.EMPTY_DATA; long adjDataTop = i - 1 >= 0 ? posData.get(i - 1) : ColumnFormat.EMPTY_DATA;
long adjDataBot = i + 1 < posData.size() ? posData.get(i + 1) : DataPointUtil.EMPTY_DATA; long adjDataBot = i + 1 < posData.size() ? posData.get(i + 1) : ColumnFormat.EMPTY_DATA;
// We send the call to create the vertices // We send the call to create the vertices
if(DataPointUtil.getAlpha(data) == 255 || !a7LodRenderer.transparencyEnabled) if(ColumnFormat.getAlpha(data) == 255 || !a7LodRenderer.transparencyEnabled)
{ {
CubicLodTemplate.addLodToBuffer(data, adjDataTop, adjDataBot, adjData, detailLevel, CubicLodTemplate.addLodToBuffer(data, adjDataTop, adjDataBot, adjData, detailLevel,
x, z, quadBuilderOpaque, debugMode); x, z, quadBuilderOpaque, debugMode);
@@ -1,14 +0,0 @@
package com.seibel.lod.core.a7.datatype.full;
public enum EGenMode {
Empty,
Surface,
Feature,
Complete;
public static EGenMode get(byte genMode) {
return EGenMode.values()[genMode];
}
public static byte get(EGenMode genMode) {
return (byte) genMode.ordinal();
}
}
@@ -1,6 +1,5 @@
package com.seibel.lod.core.a7.datatype.full; package com.seibel.lod.core.a7.datatype.full;
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
import com.seibel.lod.core.a7.datatype.full.accessor.FullArrayView; import com.seibel.lod.core.a7.datatype.full.accessor.FullArrayView;
import com.seibel.lod.core.a7.datatype.full.accessor.SingleFullArrayView; import com.seibel.lod.core.a7.datatype.full.accessor.SingleFullArrayView;
import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.level.ILevel;
@@ -8,21 +7,13 @@ import com.seibel.lod.core.a7.pos.DhBlockPos2D;
import com.seibel.lod.core.a7.pos.DhLodPos; import com.seibel.lod.core.a7.pos.DhLodPos;
import com.seibel.lod.core.a7.save.io.file.DataMetaFile; import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
import com.seibel.lod.core.a7.datatype.LodDataSource; import com.seibel.lod.core.a7.datatype.LodDataSource;
import com.seibel.lod.core.a7.util.IdMappingUtil;
import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.pos.DhSectionPos;
import com.seibel.lod.core.a7.util.UnclosableInputStream; import com.seibel.lod.core.a7.util.UnclosableInputStream;
import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.*; import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public class FullDataSource extends FullArrayView implements LodDataSource { // 1 chunk public class FullDataSource extends FullArrayView implements LodDataSource { // 1 chunk
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final Logger LOGGER = DhLoggerBuilder.getLogger();
@@ -1,19 +0,0 @@
package com.seibel.lod.core.a7.generation;
import com.seibel.lod.core.a7.datatype.full.ChunkSizedData;
import com.seibel.lod.core.a7.util.CombinableResult;
import java.util.ArrayList;
public class GenerationResult implements CombinableResult<GenerationResult> {
public final ArrayList<ChunkSizedData> dataList = new ArrayList<>();
@Override
public GenerationResult combineWith(GenerationResult b, GenerationResult c, GenerationResult d) {
dataList.ensureCapacity(dataList.size() + b.dataList.size() + c.dataList.size() + d.dataList.size());
dataList.addAll(b.dataList);
dataList.addAll(c.dataList);
dataList.addAll(d.dataList);
return this;
}
}
@@ -1,4 +0,0 @@
package com.seibel.lod.core.a7.save.io;
public class LevelFileHandler {
}
@@ -8,8 +8,6 @@ import com.seibel.lod.core.wrapperInterfaces.world.IServerLevelWrapper;
import java.io.File; import java.io.File;
public class LocalSaveStructure extends SaveStructure { public class LocalSaveStructure extends SaveStructure {
private static final IMinecraftSharedWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class);
private File debugPath = new File(""); private File debugPath = new File("");
// Fit for Client_Server & Server_Only environment // Fit for Client_Server & Server_Only environment
@@ -1,6 +0,0 @@
package com.seibel.lod.core.a7.util;
public class IOUtil {
public static final String LOD_FILE_EXTENSION = ".lod";
}
@@ -1,6 +0,0 @@
package com.seibel.lod.core.a7.util;
public class IdMappingUtil {
public static final String BLOCKSTATE_ID_AIR = "air";
//TODO HERE
}
@@ -19,12 +19,12 @@
package com.seibel.lod.core.builders.lodBuilding.bufferBuilding; package com.seibel.lod.core.builders.lodBuilding.bufferBuilding;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnFormat;
import com.seibel.lod.core.enums.rendering.EDebugMode; import com.seibel.lod.core.enums.rendering.EDebugMode;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView; import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView;
import com.seibel.lod.core.a7.datatype.column.render.ColumnBox; import com.seibel.lod.core.a7.datatype.column.render.ColumnBox;
import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.ColorUtil;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.LevelPosUtil; import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
@@ -43,14 +43,14 @@ public class CubicLodTemplate
{ {
short width = (short) (1 << detailLevel); short width = (short) (1 << detailLevel);
short x = (short) LevelPosUtil.convert(detailLevel, offsetPosX, LodUtil.BLOCK_DETAIL_LEVEL); short x = (short) LevelPosUtil.convert(detailLevel, offsetPosX, LodUtil.BLOCK_DETAIL_LEVEL);
short y = DataPointUtil.getDepth(data); short y = ColumnFormat.getDepth(data);
short z = (short) LevelPosUtil.convert(detailLevel, offsetOosZ, LodUtil.BLOCK_DETAIL_LEVEL); short z = (short) LevelPosUtil.convert(detailLevel, offsetOosZ, LodUtil.BLOCK_DETAIL_LEVEL);
short dy = (short) (DataPointUtil.getHeight(data) - y); short dy = (short) (ColumnFormat.getHeight(data) - y);
if (dy == 0) if (dy == 0)
return; return;
if (dy < 0) if (dy < 0)
{ {
throw new IllegalArgumentException("Negative y size for the data! Data: " + DataPointUtil.toString(data)); throw new IllegalArgumentException("Negative y size for the data! Data: " + ColumnFormat.toString(data));
} }
int color; int color;
@@ -62,9 +62,9 @@ public class CubicLodTemplate
float saturationMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier(); float saturationMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier();
float brightnessMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier(); float brightnessMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier();
if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) { if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) {
color = DataPointUtil.getColor(data); color = ColumnFormat.getColor(data);
} else { } else {
float[] ahsv = ColorUtil.argbToAhsv(DataPointUtil.getColor(data)); float[] ahsv = ColorUtil.argbToAhsv(ColumnFormat.getColor(data));
color = ColorUtil.ahsvToArgb(ahsv[0], ahsv[1], ahsv[2] * saturationMultiplier, ahsv[3] * brightnessMultiplier); color = ColorUtil.ahsvToArgb(ahsv[0], ahsv[1], ahsv[2] * saturationMultiplier, ahsv[3] * brightnessMultiplier);
//ApiShared.LOGGER.info("Raw color:[{}], AHSV:{}, Out color:[{}]", //ApiShared.LOGGER.info("Raw color:[{}], AHSV:{}, Out color:[{}]",
// ColorUtil.toString(DataPointUtil.getColor(data)), // ColorUtil.toString(DataPointUtil.getColor(data)),
@@ -82,7 +82,7 @@ public class CubicLodTemplate
case SHOW_GENMODE: case SHOW_GENMODE:
case SHOW_GENMODE_WIREFRAME: case SHOW_GENMODE_WIREFRAME:
{ {
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[DataPointUtil.getGenerationMode(data)]; color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[ColumnFormat.getGenerationMode(data)];
fullBright = true; fullBright = true;
break; break;
} }
@@ -100,8 +100,8 @@ public class CubicLodTemplate
width, dy, width, // setWidth width, dy, width, // setWidth
x, y, z, // setOffset x, y, z, // setOffset
color, // setColor color, // setColor
DataPointUtil.getLightSky(data), // setSkyLights ColumnFormat.getLightSky(data), // setSkyLights
fullBright ? 15 : DataPointUtil.getLightBlock(data), // setBlockLights fullBright ? 15 : ColumnFormat.getLightBlock(data), // setBlockLights
topData, botData, adjData); // setAdjData topData, botData, adjData); // setAdjData
} }
} }
@@ -23,14 +23,9 @@ import com.seibel.lod.core.a7.generation.IChunkGenerator;
import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.level.ILevel;
import com.seibel.lod.core.config.Config; import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.enums.config.EDistanceGenerationMode; import com.seibel.lod.core.enums.config.EDistanceGenerationMode;
import com.seibel.lod.core.enums.config.EGenerationPriority;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.objects.PosToGenerateContainer;
import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.gridList.ArrayGridList;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -141,25 +141,11 @@ public class Config
+ " but will increase memory and GPU usage.") + " but will increase memory and GPU usage.")
.build(); .build();
public static ConfigEntry<EDropoffQuality> dropoffQuality = new ConfigEntry.Builder<EDropoffQuality>()
.set(EDropoffQuality.AUTO)
.comment(""
+ "This determines how lod level drop off will be done. \n"
+ "\n"
+ EDropoffQuality.SMOOTH_DROPOFF + ": \n"
+ " The lod level is calculated for each point, making the drop off a smooth circle. \n"
+ EDropoffQuality.PERFORMANCE_FOCUSED + ": \n"
+ " One detail level for an entire region. Minimize CPU usage and \n"
+ " improve terrain refresh delay, especially for high Lod render distance. \n"
+ EDropoffQuality.AUTO + ": \n"
+ " Use "+ EDropoffQuality.SMOOTH_DROPOFF + " for less then 128 Lod render distance, \n"
+ " or "+ EDropoffQuality.PERFORMANCE_FOCUSED +" otherwise.")
.build();
public static ConfigEntry<ETransparency> transparency = new ConfigEntry.Builder<ETransparency>() public static ConfigEntry<ETransparency> transparency = new ConfigEntry.Builder<ETransparency>()
.set(ETransparency.COMPLETE) .set(ETransparency.COMPLETE)
.comment("") .comment("")
.build(); .build();
public static ConfigEntry<Integer> lodBiomeBlending = new ConfigEntry.Builder<Integer>() public static ConfigEntry<Integer> lodBiomeBlending = new ConfigEntry.Builder<Integer>()
.setMinDefaultMax(0,1,7) .setMinDefaultMax(0,1,7)
.comment("" .comment(""
@@ -1,64 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.dataFormat;
public class ColorFormat
{
public final static int BLUE_SHIFT = 0;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8;
public final static int RED_SHIFT = BLUE_SHIFT + 16;
public final static int ALPHA_SHIFT = BLUE_SHIFT + 24;
public final static long ALPHA_MASK = 0b1111;
public final static long RED_MASK = 0b1111_1111;
public final static long GREEN_MASK = 0b1111_1111;
public final static long BLUE_MASK = 0b1111_1111;
public static int createColorData(int alpha, int red, int green, int blue)
{
int colorData = 0;
colorData += (alpha & ALPHA_MASK) << ALPHA_SHIFT;
colorData += (red & RED_MASK) << RED_SHIFT;
colorData += (green & GREEN_MASK) << GREEN_SHIFT;
colorData += (blue & BLUE_MASK) << BLUE_SHIFT;
return colorData;
}
public static short getAlpha(long dataPoint)
{
return (short) ((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK);
}
public static short getRed(long dataPoint)
{
return (short) ((dataPoint >>> RED_SHIFT) & RED_MASK);
}
public static short getGreen(long dataPoint)
{
return (short) ((dataPoint >>> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(long dataPoint)
{
return (short) ((dataPoint >>> BLUE_SHIFT) & BLUE_MASK);
}
}
@@ -1,49 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.dataFormat;
@Deprecated //Unused
public class DataMergeUtil
{
public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize)
{
start *= packetSize;
length *= packetSize;
arraySize *= packetSize;
for (int i = 0; i < arraySize - start; i++)
{
array[start + i] = array[start + length + i];
//remove comment to not leave garbage at the end
//array[start + packetSize + i] = 0;
}
}
public static void extendArray(short[] array, int packetSize, int start, int length, int arraySize)
{
start *= packetSize;
length *= packetSize;
arraySize *= packetSize;
for (int i = arraySize - start - 1; i >= 0; i--)
{
array[start + length + i] = array[start + i];
array[start + i] = 0;
}
}
}
@@ -1,58 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.dataFormat;
public class LightFormat
{
public final static byte INT_BLOCK_LIGHT_SHIFT = 16;
public final static byte INT_SKY_LIGHT_SHIFT = 0;
public final static byte BYTE_BLOCK_LIGHT_SHIFT = 4;
public final static byte BYTE_SKY_LIGHT_SHIFT = 0;
public final static byte BLOCK_LIGHT_MASK = 0b1111;
public final static byte SKY_LIGHT_MASK = 0b1111;
public static byte formatLightAsByte(byte skyLight, byte blockLight)
{
return (byte) (((skyLight & SKY_LIGHT_MASK) << (BYTE_SKY_LIGHT_SHIFT + 4)) | ((blockLight & BLOCK_LIGHT_MASK) << (BYTE_BLOCK_LIGHT_SHIFT + 4)));
}
public static int formatLightAsInt(byte skyLight, byte blockLight)
{
return ((skyLight & SKY_LIGHT_MASK) << INT_SKY_LIGHT_SHIFT) | ((blockLight & BLOCK_LIGHT_MASK) << INT_BLOCK_LIGHT_SHIFT);
}
public static int convertByteToIntFormat(byte lights)
{
return formatLightAsInt((byte) ((lights >>> BYTE_SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK), (byte) ((lights >>> BYTE_BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK));
}
public static byte getSkyLight(byte lights)
{
return (byte) ((lights >>> BYTE_SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getBlockLight(byte lights)
{
return (byte) ((lights >>> BYTE_BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
}
@@ -1,104 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.dataFormat;
public class PositionDataFormat
{
public final static byte LOD_COUNT_SHIFT = 6;
public final static byte CORRECT_LIGHT_SHIFT = 5;
public final static byte GEN_TYPE_SHIFT = 2;
public final static byte VOID_SHIFT = 1;
public final static byte EXISTENCE_SHIFT = 0;
//We are able to count up to 64 different lods in a column
public final static short LOD_COUNT_MASK = 0b11_1111;
public final static short CORRECT_LIGHT_MASK = 0b1;
public final static short GEN_TYPE_MASK = 0b111;
public final static short VOID_MASK = 0b1;
public final static short EXISTENCE_MASK = 0b1;
public final static int EMPTY_DATA = 0;
public final static int VOID_DATA = VOID_MASK<<VOID_SHIFT + EXISTENCE_MASK<<EXISTENCE_SHIFT;
public static short createVoidPositionData(byte generationMode)
{
short positionData = 0;
positionData |= (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
positionData |= VOID_MASK << VOID_SHIFT;
positionData |= EXISTENCE_MASK << EXISTENCE_SHIFT;
return positionData;
}
public static short createPositionData(int lodCount, boolean correctLight, byte generationMode)
{
short positionData = 0;
positionData |= (lodCount & LOD_COUNT_MASK) << LOD_COUNT_SHIFT;
positionData |= (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
if (correctLight)
positionData |= CORRECT_LIGHT_MASK << CORRECT_LIGHT_SHIFT;
positionData |= EXISTENCE_MASK << EXISTENCE_SHIFT;
return positionData;
}
public static byte getLodCount(short dataPoint)
{
return (byte) ((dataPoint >>> LOD_COUNT_SHIFT) & LOD_COUNT_MASK);
}
public static boolean getFlag(short dataPoint)
{
return ((dataPoint >>> CORRECT_LIGHT_SHIFT) & CORRECT_LIGHT_MASK) == 1;
}
public static byte getGenerationMode(short dataPoint)
{
return (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
}
public static boolean isVoid(short dataPoint)
{
return (((dataPoint >>> VOID_SHIFT) & VOID_MASK) == 1);
}
public static boolean doesItExist(short dataPoint)
{
return (((dataPoint >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1);
}
public static short setLodCount(short dataPoint, short lodCount)
{
return (short) (dataPoint | ((lodCount & LOD_COUNT_MASK) << LOD_COUNT_SHIFT));
}
public static short setFlag(short dataPoint)
{
return (short) (dataPoint | ((CORRECT_LIGHT_MASK) << CORRECT_LIGHT_SHIFT));
}
public static short setGenerationMode(short dataPoint, byte generationMode)
{
return (short) (dataPoint | ((generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT));
}
public static short setVoid(short dataPoint)
{
return (short) (dataPoint | (VOID_MASK << VOID_SHIFT));
}
public static short setExistence(short dataPoint)
{
return (short) (dataPoint | (EXISTENCE_MASK << EXISTENCE_SHIFT));
}
}
@@ -1,130 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.dataFormat;
public class VerticalDataFormat
{
public final static short MIN_WORLD_HEIGHT = -2048;
public final static short MAX_WORLD_HEIGHT = 2047;
public final static byte HEIGHT_SHIFT = 20;
public final static byte DEPTH_SHIFT = 8;
public final static byte LEVEL_SHIFT = 3;
public final static byte BOTTOM_TYPE_SHIFT = 2;
public final static byte TRANSPARENCY_SHIFT = 1;
public final static byte EXISTENCE_SHIFT = 0;
public final static int FULL_MASK = ~0;
public final static int HEIGHT_MASK = 0b1111_1111_1111;
public final static int DEPTH_MASK = 0b1111_1111_1111;
public final static int LEVEL_MASK = 0b111;
public final static int TRANSPARENCY_MASK = 0b1;
public final static int BOTTOM_TYPE_MASK = 0b1;
public final static int EXISTENCE_MASK = 0b1;
public final static int HEIGHT_RESET = ~(HEIGHT_MASK << HEIGHT_SHIFT);
public final static int DEPTH_RESET = ~(DEPTH_MASK << DEPTH_SHIFT);
public final static int LEVEL_RESET = ~(LEVEL_MASK << LEVEL_SHIFT);
public final static int TRANSPARENCY_RESET = ~(TRANSPARENCY_MASK << BOTTOM_TYPE_SHIFT);
public final static int BOTTOM_TYPE_RESET = ~(BOTTOM_TYPE_MASK << TRANSPARENCY_SHIFT);
public final static int EXISTENCE_RESET = ~(EXISTENCE_MASK << EXISTENCE_SHIFT);
public final static int EMPTY_LOD = 0;
public static int createVerticalData(int height, int depth, int level, boolean transparent, boolean bottom)
{
int verticalData = 0;
verticalData |= (height & HEIGHT_MASK) << HEIGHT_SHIFT;
verticalData |= (depth & DEPTH_MASK) << DEPTH_SHIFT;
verticalData |= (level & LEVEL_MASK) << LEVEL_SHIFT;
if (bottom)
verticalData |= BOTTOM_TYPE_MASK << BOTTOM_TYPE_SHIFT;
if (transparent)
verticalData |= TRANSPARENCY_MASK << TRANSPARENCY_SHIFT;
verticalData |= EXISTENCE_MASK << EXISTENCE_SHIFT;
return verticalData;
}
public static short getHeight(int verticalData)
{
return (short) ((verticalData >>> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(int verticalData)
{
return (short) ((verticalData >>> DEPTH_SHIFT) & DEPTH_MASK);
}
public static byte getLevel(int verticalData)
{
return (byte) ((verticalData >>> LEVEL_SHIFT) & LEVEL_MASK);
}
public static boolean isTransparent(int verticalData)
{
return ((verticalData >>> TRANSPARENCY_SHIFT) & TRANSPARENCY_MASK) == 1;
}
public static boolean isBottom(int verticalData)
{
return ((verticalData >>> BOTTOM_TYPE_SHIFT) & BOTTOM_TYPE_MASK) == 1;
}
public static boolean doesItExist(int verticalData)
{
return (((verticalData >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1);
}
public static int setHeight(int verticalData, int height)
{
return verticalData | ((height & HEIGHT_MASK) << HEIGHT_SHIFT);
}
public static int setDepth(int verticalData, int depth)
{
return verticalData | ((depth & DEPTH_MASK) << DEPTH_SHIFT);
}
public static int setLevel(int verticalData, int level)
{
return verticalData | ((level & LEVEL_MASK) << LEVEL_SHIFT);
}
public static int setTransparency(int verticalData)
{
return verticalData | ((TRANSPARENCY_MASK) << TRANSPARENCY_SHIFT);
}
public static int setBottom(int verticalData)
{
return verticalData | ((BOTTOM_TYPE_MASK) << BOTTOM_TYPE_SHIFT);
}
public static int setExistence(int verticalData)
{
return verticalData | ((EXISTENCE_MASK) << EXISTENCE_SHIFT);
}
}
@@ -27,7 +27,6 @@ package com.seibel.lod.core.enums;
* @author James Seibel * @author James Seibel
* @version 2022-7-13 * @version 2022-7-13
*/ */
@Deprecated
public enum ELevelType public enum ELevelType
{ {
SERVER_LEVEL, SERVER_LEVEL,
@@ -1,54 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2022 Tom Lee (TomTheFurry)
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.enums.config;
/**
* AUTO <br>
* SMOOTH_DROPOFF <br>
* PERFORMANCE_FOCUSED <br> <br>
*
* Determines how lod level drop off should be done
*
* @author Tom Lee
* @version 7-1-2022
*/
public enum EDropoffQuality
{
// Reminder:
// when adding items up the API minor version
// when removing items up the API major version
/** SMOOTH_DROPOFF when <128 lod view distance, or PERFORMANCE_FOCUSED otherwise */
AUTO(-1),
SMOOTH_DROPOFF(10),
PERFORMANCE_FOCUSED(0);
public final int fastModeSwitch;
EDropoffQuality(int fastModeSwitch) {
this.fastModeSwitch = fastModeSwitch;
}
}
@@ -1,65 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.handlers;
/**
*
* @author Cola
* @author Leonardo Amato
* @version 11-12-2021
*/
public class ChunkFileLoader
{
// TODO
// public static IChunk getChunkFromFile(ChunkPos pos)
// {
// LevelWrapper clientLevel = MinecraftWrapper.INSTANCE.getWrappedClientLevel();
// if (clientLevel == null)
// return null;
// WorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(clientLevel.getDimensionType());
// try
// {
// File file = new File(serverWorld.getSaveFolder().getParent() + File.separatorChar + "region", "r." + (pos.x >> 5) + "." + (pos.z >> 5) + ".mca");
// if(!file.exists())
// return null;
// IChunk loadedChunk = ChunkSerializer.read(
// serverWorld,
// serverWorld.getStructureManager(),
// serverWorld.getPoiManager(),
// pos,
// serverWorld.getChunkSource().chunkMap.read(pos)
// );
// boolean emptyChunk = true;
// for(int i = 0; i < 16; i++){
// for(int j = 0; j < 16; j++){
// emptyChunk &= loadedChunk.isYSpaceEmpty(i,j);
// }
// }
// if(emptyChunk)
// return null;
// else
// return loadedChunk;
// }
// catch (Exception e)
// {
// return null;
// }
// }
}
@@ -1,124 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.objects;
/*
import com.seibel.lod.core.wrapperInterfaces.block.BlockDetail;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class BlockBiomeCouple
{
public static final ConcurrentMap<BlockDetail, BlockBiomeCouple> noBiomeInstanceCache = new ConcurrentHashMap<>();
public static ConcurrentMap<IBiomeWrapper, ConcurrentMap<BlockDetail, BlockBiomeCouple>> withBiomeInstanceCache = new ConcurrentHashMap<>();
String blockName;
String biomeName;
String coupleName;
IBiomeWrapper biomeColor;
BlockDetail blockColor;
public static void addBlockBiomeToCache(IBlockColorWrapper blockColor){
}
public static BlockBiomeCouple getBlockBiomeCouple(IBlockColorWrapper blockColor){
if(noBiomeInstanceCache.containsKey(blockColor))
{
return noBiomeInstanceCache.get(blockColor);
}
else
{
BlockBiomeCouple couple = new BlockBiomeCouple(blockColor);
noBiomeInstanceCache.put(blockColor,couple);
return couple;
}
}
public static BlockBiomeCouple getBlockBiomeCouple(IBiomeWrapper biomeColor, IBlockColorWrapper blockColor){
if(biomeColor == null)
{
return getBlockBiomeCouple(blockColor);
}
else
{
if(withBiomeInstanceCache.containsKey(biomeColor))
{
withBiomeInstanceCache.put(biomeColor, new ConcurrentHashMap<>());
}
ConcurrentMap<IBlockColorWrapper, BlockBiomeCouple> blockToCoupleMap = withBiomeIstanceCache.get(biomeColor);
if(blockToCoupleMap.containsKey(blockColor))
{
return blockToCoupleMap.get(blockColor);
}
else
{
BlockBiomeCouple couple = new BlockBiomeCouple(blockColor,biomeColor);
blockToCoupleMap.put(blockColor,couple);
return couple;
}
}
}
public BlockBiomeCouple(IBlockColorWrapper blockColor)
{
this.biomeColor = null;
this.blockColor = blockColor;
biomeName = "";
blockName = blockColor.getName();
coupleName = blockName;
}
public BlockBiomeCouple(IBlockColorWrapper blockColor, IBiomeWrapper biomeColor)
{
this.biomeColor = biomeColor;
this.blockColor = blockColor;
if(biomeColor == null)
biomeName = biomeColor.getName();
else
biomeName = "";
blockName = blockColor.getName();
coupleName = blockName + biomeName;
}
@Override public boolean equals(Object o)
{
if (this == o)
return true;
if (!(o instanceof BlockBiomeCouple))
return false;
BlockBiomeCouple that = (BlockBiomeCouple) o;
return Objects.equals(blockName, that.blockName) && Objects.equals(biomeName, that.biomeName);
}
@Override public int hashCode()
{
return Objects.hash(blockName, biomeName);
}
}
*/
@@ -1,114 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.objects;
import com.seibel.lod.core.util.LodUtil;
/**
* This object is similar to ChunkPos or BlockPos.
*
* @author James Seibel
* @version 8-21-2021
*/
public class DHRegionPos
{
public int x;
public int z;
/** Sets x and z to 0 */
public DHRegionPos()
{
x = 0;
z = 0;
}
/** simple constructor that sets x and z to new x and z. */
public DHRegionPos(int newX, int newZ)
{
x = newX;
z = newZ;
}
/** Converts from a BlockPos to a RegionPos */
public DHRegionPos(DHBlockPos pos)
{
x = Math.floorDiv(pos.x >> 4, LodUtil.REGION_WIDTH_IN_CHUNKS);
z = Math.floorDiv(pos.z >> 4, LodUtil.REGION_WIDTH_IN_CHUNKS);
}
/** Converts from a ChunkPos to a RegionPos */
public DHRegionPos(DHChunkPos pos)
{
x = Math.floorDiv(pos.getX(), LodUtil.REGION_WIDTH_IN_CHUNKS);
z = Math.floorDiv(pos.getZ(), LodUtil.REGION_WIDTH_IN_CHUNKS);
}
public DHChunkPos centerChunkPos() {
return new DHChunkPos(x * LodUtil.REGION_WIDTH_IN_CHUNKS + LodUtil.REGION_WIDTH_IN_CHUNKS / 2,
z * LodUtil.REGION_WIDTH_IN_CHUNKS + LodUtil.REGION_WIDTH_IN_CHUNKS / 2);
}
public DHChunkPos cornerChunkPos() {
return new DHChunkPos(x * LodUtil.REGION_WIDTH_IN_CHUNKS, z * LodUtil.REGION_WIDTH_IN_CHUNKS);
}
public DHBlockPos centerBlockPos() {
return new DHBlockPos(x * LodUtil.REGION_WIDTH_IN_CHUNKS * 16 + LodUtil.REGION_WIDTH_IN_CHUNKS * 16 / 2,
0, z * LodUtil.REGION_WIDTH_IN_CHUNKS * 16 + LodUtil.REGION_WIDTH_IN_CHUNKS * 16 / 2);
}
public DHBlockPos cornerBlockPos() {
return new DHBlockPos(x * LodUtil.REGION_WIDTH_IN_CHUNKS * 16,
0, z * LodUtil.REGION_WIDTH_IN_CHUNKS * 16);
}
@Override
public boolean equals(Object o) {
// If the object is compared with itself then return true
if (o == this) {
return true;
}
// Check if o is an instance of RegionPos or not
if (!(o instanceof DHRegionPos)) {
return false;
}
DHRegionPos c = (DHRegionPos) o;
return c.x==x &&c.z==z;
}
@Override
public String toString()
{
return "(" + x + "," + z + ")";
}
public static long asLong(int i, int j) {
return (long)i & 0xFFFFFFFFL | ((long)j & 0xFFFFFFFFL) << 32;
}
public static int getX(long l) {
return (int)(l & 0xFFFFFFFFL);
}
public static int getZ(long l) {
return (int)(l >>> 32 & 0xFFFFFFFFL);
}
@Override
public int hashCode() {
return Long.hashCode(asLong(x,z));
}
}
@@ -1,51 +0,0 @@
package com.seibel.lod.core.objects;
import com.seibel.lod.core.util.DataPointUtil;
public final class LodDataView {
private final long[] data;
private final int size;
private final int offset;
public LodDataView(long[] data, int size, int offset) {
this.data = data;
this.size = size;
this.offset = offset;
}
public long get(int index) {
return data[index + offset];
}
public void set(int index, long value) {
data[index + offset] = value;
}
public int size() {
return size;
}
public void copyTo(long[] target, int offset) {
System.arraycopy(data, this.offset, target, offset, size);
}
public void copyTo(LodDataView target) {
System.arraycopy(data, this.offset, target.data, target.offset, size);
}
public boolean mergeWith(LodDataView source, int verticalSize, boolean override) {
if (size != source.size) {
throw new IllegalArgumentException("Cannot merge views of different sizes");
}
boolean anyChange = false;
for (int o=0; o<(source.size()*verticalSize); o+=verticalSize) {
if (override) {
if (DataPointUtil.compareDatapointPriority(source.get(o), get(o)) >= 0) {
anyChange = true;
System.arraycopy(source.data, source.offset+o, data, offset+o, verticalSize);
}
} else {
if (DataPointUtil.compareDatapointPriority(source.get(o), get(o)) > 0) {
anyChange = true;
System.arraycopy(source.data, source.offset+o, data, offset+o, verticalSize);
}
}
}
return anyChange;
}
}
@@ -33,9 +33,9 @@ public class ParsedIp
/** /**
* Can be used to find if a numeric IP is a LAN IP * Can be used to find if a numeric IP is a LAN IP
* *
* Ip list source: <br> * Ip list source: <br>
* https://networkengineering.stackexchange.com/questions/5825/why-192-168-for-local-addresses * <a href="https://networkengineering.stackexchange.com/questions/5825/why-192-168-for-local-addresses">...</a>
*/ */
public static final String LAN_IP_REGEX = "(10|172\\.16|192\\.168).*"; public static final String LAN_IP_REGEX = "(10|172\\.16|192\\.168).*";
@@ -1,224 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.objects;
import com.seibel.lod.core.util.LevelPosUtil;
/**
* Holds the levelPos that need to be generated.
*
* @author Leonardo Amato
* @version 9-27-2021
*/
public class PosToGenerateContainer
{
private final int playerPosX;
private final int playerPosZ;
private int nearSize;
private int farSize;
// TODO what is the format of these two arrays? [detailLevel][4-children]?
private final int[][] nearPosToGenerate;
private final int[][] farPosToGenerate;
public PosToGenerateContainer(int maxDataToGenerate, int playerPosX, int playerPosZ)
{
this.playerPosX = playerPosX;
this.playerPosZ = playerPosZ;
nearSize = 0;
farSize = 0;
nearPosToGenerate = new int[maxDataToGenerate][4];
farPosToGenerate = new int[maxDataToGenerate][4];
}
// TODO what is going on in this method?
public void addNearPosToGenerate(byte detailLevel, int posX, int posZ, boolean sort)
{
// FIXME: This is a cast from double to int!!! OVERFLOW MAY HAPPEN!
int distance = (int)LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ);
int index;
//We are introducing a position in the near array
index = nearSize;
if (index == nearPosToGenerate.length) {
if (Integer.compare(distance, nearPosToGenerate[index - 1][3]) > 0) {
return;
}
index--;
} else nearSize++;
if (sort) {
while (index > 0 && Integer.compare(distance, nearPosToGenerate[index - 1][3]) <= 0)
{
nearPosToGenerate[index][0] = nearPosToGenerate[index - 1][0];
nearPosToGenerate[index][1] = nearPosToGenerate[index - 1][1];
nearPosToGenerate[index][2] = nearPosToGenerate[index - 1][2];
nearPosToGenerate[index][3] = nearPosToGenerate[index - 1][3];
index--;
}
}
nearPosToGenerate[index][0] = detailLevel + 1;
nearPosToGenerate[index][1] = posX;
nearPosToGenerate[index][2] = posZ;
nearPosToGenerate[index][3] = distance;
}
// TODO what is going on in this method?
public void addFarPosToGenerate(byte detailLevel, int posX, int posZ, boolean sort)
{
// FIXME: This is a cast from double to int!!! OVERFLOW MAY HAPPEN!
int distance = (int)LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ);
int index;
// We are introducing a position in the far array
index = farSize;
if (index == farPosToGenerate.length) {
if (Integer.compare(distance, farPosToGenerate[index - 1][3]) > 0) {
return;
}
index--;
} else farSize++;
if (sort) {
while (index > 0 && Integer.compare(distance, farPosToGenerate[index - 1][3]) <= 0)
{
farPosToGenerate[index][0] = farPosToGenerate[index - 1][0];
farPosToGenerate[index][1] = farPosToGenerate[index - 1][1];
farPosToGenerate[index][2] = farPosToGenerate[index - 1][2];
farPosToGenerate[index][3] = farPosToGenerate[index - 1][3];
index--;
}
}
farPosToGenerate[index][0] = detailLevel + 1;
farPosToGenerate[index][1] = posX;
farPosToGenerate[index][2] = posZ;
farPosToGenerate[index][3] = distance;
}
public boolean isFull() {
return nearSize == nearPosToGenerate.length && farSize == farPosToGenerate.length;
}
public int getNumberOfPos()
{
return nearSize + farSize;
}
public int getNumberOfNearPos()
{
return nearSize;
}
public int getNumberOfFarPos()
{
return farSize;
}
public int getMaxNumberOfNearPos()
{
return nearPosToGenerate.length;
}
public int getMaxNumberOfFarPos()
{
return farPosToGenerate.length;
}
// TODO what does getNth mean? could the name be more descriptive or is it just a index?
public int getNthDetail(int n, boolean near)
{
if (near)
return nearPosToGenerate[n][0];
else
return farPosToGenerate[n][0];
}
public int getNthPosX(int n, boolean near)
{
if (near)
return nearPosToGenerate[n][1];
else
return farPosToGenerate[n][1];
}
public int getNthPosZ(int n, boolean near)
{
if (near)
return nearPosToGenerate[n][2];
else
return farPosToGenerate[n][2];
}
public int getNthGeneration(int n, boolean near)
{
if (near)
return nearPosToGenerate[n][3];
else
return farPosToGenerate[n][3];
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append('\n');
builder.append('\n');
builder.append('\n');
builder.append("near pos to generate");
builder.append('\n');
for (int[] ints : nearPosToGenerate)
{
if (ints[0] == 0)
break;
builder.append(ints[0] - 1);
builder.append(" ");
builder.append(ints[1]);
builder.append(" ");
builder.append(ints[2]);
builder.append(" ");
builder.append(ints[3]);
builder.append('\n');
}
builder.append('\n');
builder.append("far pos to generate");
builder.append('\n');
for (int[] ints : farPosToGenerate)
{
if (ints[0] == 0)
break;
builder.append(ints[0] - 1);
builder.append(" ");
builder.append(ints[1]);
builder.append(" ");
builder.append(ints[2]);
builder.append(" ");
builder.append(ints[3]);
builder.append('\n');
}
return builder.toString();
}
}
@@ -1,138 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.objects.lod;
import com.seibel.lod.core.objects.LodDataView;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* A level container is a quad tree level
*/
public interface LevelContainer
{
/**
* With this you can add data to the level container
* @param data actual data to add in an array of long format.
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @param index vertical position in the detail level
* @return true if correctly added, false otherwise
*/
boolean addData(long data, int posX, int posZ, int index);
/**
* With this you can add data to the level container
* @param data actual data to add in an array of long[] format.
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return true if correctly changed, false otherwise
*/
@Deprecated
boolean addVerticalData(long[] data, int posX, int posZ, boolean override);
boolean copyVerticalData(LodDataView data, int posX, int posZ, boolean override);
/**
* With this you can add a square of data to the level container
* @return true if anything changed, false otherwise
*/
@Deprecated
boolean addChunkOfData(long[] data, int posX, int posZ, int widthX, int widthZ, boolean override);
boolean copyChunkOfData(LodDataView data, int posX, int posZ, int widthX, int widthZ, boolean override);
/**
* With this you can get data from the level container
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return the data in long array format
*/
long getData(int posX, int posZ, int index);
/**
* With this you can get data from the level container
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return the data in long array format
*/
@Deprecated
long[] getAllData(int posX, int posZ);
LodDataView getVerticalDataView(int posX, int posZ);
/**
* With this you can get data from the level container
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return the data in long array format
*/
long getSingleData(int posX, int posZ);
/**
* @param posX x position in the detail level
* @param posZ z position in the detail level
* @return true only if the data exist
*/
boolean doesItExist(int posX, int posZ);
/**
* @return return the detailLevel of this level container
*/
byte getDetailLevel();
int getVerticalSize();
/** Clears the dataPoint at the given array index */
void clear(int posX, int posZ);
/**
* This return a level container with detail level lower than the current level.
* The new level container may use information of this level.
* @return the new level container
*/
LevelContainer expand();
/**
* @param lowerLevelContainer lower level where we extract the data
* @param posX x position in the detail level to update
* @param posZ z position in the detail level to update
*/
void updateData(LevelContainer lowerLevelContainer, int posX, int posZ);
/**
* This will write the raw data with metadata to the output stream
* @return isAllGenerated whether the data is all generated
* @throws IOException
*/
boolean writeData(DataOutputStream output) throws IOException;
/**
* This will give the data to save in the file
* @return data as a String
*/
int getMaxNumberOfLods();
/**
* This will return a ram usage estimation of this object
* @return long as byte
*/
long getRoughRamUsage();
}
@@ -1,604 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.objects.lod;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.enums.config.EDistanceGenerationMode;
import com.seibel.lod.core.enums.config.EDropoffQuality;
import com.seibel.lod.core.enums.config.EGenerationPriority;
import com.seibel.lod.core.enums.config.EVerticalQuality;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.objects.*;
import com.seibel.lod.core.util.DataPointUtil;
import com.seibel.lod.core.util.DetailDistanceUtil;
import com.seibel.lod.core.util.LevelPosUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
/**
* This object holds all loaded LevelContainers acting as a quad tree for a
* given region. <Br>
* <Br>
*
* <strong>Coordinate Standard: </strong><br>
* Coordinate called posX or posZ are relative LevelPos coordinates <br>
* unless stated otherwise. <br>
*
* @author Leonardo Amato
* @version 10-10-2021
*/
public class LodRegion {
private static final ILodConfigWrapperSingleton CONFIG = SingletonInjector.INSTANCE.get(ILodConfigWrapperSingleton.class);
/** Number of detail level supported by a region */
private static final byte POSSIBLE_LOD = LodUtil.DETAIL_OPTIONS;
/** Holds the lowest (least detailed) detail level in this region */
private volatile byte minDetailLevel;
public byte lastMaxDetailLevel = LodUtil.REGION_DETAIL_LEVEL;
/**
* This holds all data for this region
*/
private final LevelContainer[] dataContainer;
/** This chunk Pos has been generated */
// private final boolean[] preGeneratedChunkPos;
/** the vertical quality of this region */
private final EVerticalQuality verticalQuality;
/** this region's x RegionPos */
public final int regionPosX;
/** this region's z RegionPos */
public final int regionPosZ;
public volatile boolean needRecheckGenPoint = true;
//public volatile int needRegenBuffer = 2; MOVED TO RENDERREGION!
public volatile boolean needSignalToRegenBuffer = true;
public volatile boolean needSaving = false;
public final AtomicInteger isWriting = new AtomicInteger(0);
public static byte calculateFarModeSwitch(byte targetLevel) {
if (targetLevel==0) return 0; // Always use detail 0 if it's way too close
double part = targetLevel / (double)LodUtil.REGION_DETAIL_LEVEL;
byte farModeLevel = LodUtil.DETAIL_OPTIONS-(LodUtil.CHUNK_DETAIL_LEVEL+1);
farModeLevel *= part;
farModeLevel += (LodUtil.CHUNK_DETAIL_LEVEL+1);
return (byte)LodUtil.clamp(LodUtil.CHUNK_DETAIL_LEVEL+1, farModeLevel, LodUtil.DETAIL_OPTIONS - 1);
}
public LodRegion(byte minDetailLevel, DHRegionPos regionPos, EVerticalQuality verticalQuality) {
this.minDetailLevel = minDetailLevel;
this.regionPosX = regionPos.x;
this.regionPosZ = regionPos.z;
this.verticalQuality = verticalQuality;
dataContainer = new LevelContainer[POSSIBLE_LOD];
// Initialize all the different matrices
for (byte lod = minDetailLevel; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++) {
dataContainer[lod] = new VerticalLevelContainer(lod);
}
}
/**
* Inserts the data point into the region.
* <p>
*
* @return true if the data was added successfully
*/
public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data) {
if(isWriting.get()<=0) throw new ConcurrentModificationException("isWriting counter lock should have been acquired!");
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
// The dataContainer could have null entries if the
// detailLevel changes.
if (this.dataContainer[detailLevel] == null)
return false;// this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
this.dataContainer[detailLevel].addData(data, posX, posZ, verticalIndex);
return true;
}
/**
* Inserts the vertical data into the region.
* <p>
*
* @return true if the data was added successfully
*/
public boolean addVerticalData(byte detailLevel, int posX, int posZ, long[] data, boolean override) {
if(isWriting.get()<=0) throw new ConcurrentModificationException("isWriting counter lock should have been acquired!");
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
// The dataContainer could have null entries if the
// detailLevel changes.
if (this.dataContainer[detailLevel] == null)
return false;// this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
boolean updated = this.dataContainer[detailLevel].addVerticalData(data, posX, posZ, override);
if (updated) {
needSignalToRegenBuffer = true;
needSaving = true;
}
return updated;
}
/**
* Inserts the vertical data into the region.
* <p>
*
* @return true if the data was added successfully
*/
public boolean addChunkOfData(byte detailLevel, int posX, int posZ, int widthX, int widthZ, long[] data, int verticalSize, boolean override) {
if(isWriting.get()<=0) throw new ConcurrentModificationException("isWriting counter lock should have been acquired!");
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
// The dataContainer could have null entries if the
// detailLevel changes.
if (this.dataContainer[detailLevel] == null)
return false;// this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
if (this.dataContainer[detailLevel].getVerticalSize() != verticalSize) {
throw new RuntimeException(
String.format("Provided data's verticalSize [%d]" +
" is different from current storage's verticalSize [%d] at detail [%d]",
verticalSize, this.dataContainer[detailLevel].getVerticalSize(), detailLevel));
}
boolean updated = this.dataContainer[detailLevel].addChunkOfData(data, posX, posZ, widthX, widthZ, override);
//ApiShared.LOGGER.info("addChunkOfData(region:{}, level:{}, x:{}, z:{}, wx:{}, wz:{}, override:{}, updated:{})",
// getRegionPos(), detailLevel, posX, posZ, widthX, widthZ, override, updated);
if (updated) {
needSignalToRegenBuffer = true;
needSaving = true;
} else {
/*ApiShared.LOGGER.info("addChunkOfData nothing changed. Datapoint: {}\n Upper Datapoint: {}",
DataPointUtil.toString(this.dataContainer[detailLevel].getSingleData(posX, posZ)),
DataPointUtil.toString(this.dataContainer[9].getSingleData(0, 0))
);*/
}
if (!doesDataExist(detailLevel, posX, posZ, EDistanceGenerationMode.values()[DataPointUtil.getGenerationMode(data[0]) - 1])) { //FIXME: -1 case NONE has value of 1 but slot of 0
throw new RuntimeException("Data still doesn't exist after addChunkOfData!");
}
return updated;
}
/**
* Get the dataPoint at the given relative position.
*
* @return the data at the relative pos and detail level, 0 if the data doesn't
* exist.
*/
public long getData(byte detailLevel, int posX, int posZ, int verticalIndex) {
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].getData(posX, posZ, verticalIndex);
}
/**
* Get the dataPoint at the given relative position.
*
* @return the data at the relative pos and detail level, 0 if the data doesn't
* exist.
*/
@Deprecated
public long[] getAllData(byte detailLevel, int posX, int posZ) {
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].getAllData(posX, posZ);
}
public LodDataView getDataView(byte detailLevel, int posX, int posZ) {
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].getVerticalDataView(posX, posZ);
}
/**
* Get the dataPoint at the given relative position.
*
* @return the data at the relative pos and detail level, 0 if the data doesn't
* exist.
*/
public long getSingleData(byte detailLevel, int posX, int posZ) {
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].getSingleData(posX, posZ);
}
/**
* This method will fill the posToGenerate array with all levelPos that are
* render-able.
* <p>
* TODO why don't we return the posToGenerate, it would make this easier to
* understand
*/
public void getPosToGenerate(PosToGenerateContainer posToGenerate, int playerBlockPosX, int playerBlockPosZ,
EGenerationPriority priority, EDistanceGenerationMode genMode, boolean shouldSort) {
getPosToGenerate(posToGenerate, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerBlockPosX, playerBlockPosZ,
priority, genMode, shouldSort, true);
}
/**
* A recursive method that fills the posToGenerate array with all levelPos that
* need to be generated.
* <p>
* TODO why don't we return the posToGenerate, it would make this easier to
* understand
* FIXME This is.... absolute hell currently. Needs clean up.
*/
private void getPosToGenerate(PosToGenerateContainer posToGenerate, byte detailLevel, int offsetPosX, int offsetPosZ,
int playerPosX, int playerPosZ, EGenerationPriority priority, EDistanceGenerationMode genMode, boolean shouldSort, boolean needFarPos) {
// equivalent to 2^(...)
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
// calculate what LevelPos are in range to generate
double minDistance = LevelPosUtil.minDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ);
// determine this child's levelPos
byte childDetailLevel = (byte) (detailLevel - 1);
int childOffsetPosX = offsetPosX * 2;
int childOffsetPosZ = offsetPosZ * 2;
EDistanceGenerationMode testerGenMode = genMode;//detailLevel >= LodUtil.CHUNK_DETAIL_LEVEL ? DistanceGenerationMode.NONE : genMode;
byte targetDetailLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
int farModeSwitchLevel = (priority == EGenerationPriority.NEAR_FIRST) ? -1 : calculateFarModeSwitch(targetDetailLevel);
if (priority == EGenerationPriority.FAR_FIRST) farModeSwitchLevel = 8;
boolean doesDataExist = doesDataExist(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size, testerGenMode);
boolean isFarModeSwitchEdge = needFarPos && detailLevel <= farModeSwitchLevel;
if (isFarModeSwitchEdge) needFarPos = false;
if (targetDetailLevel >= detailLevel) {
if (!doesDataExist) {
if (isFarModeSwitchEdge)
posToGenerate.addFarPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
offsetPosZ + regionPosZ * size, shouldSort);
else
posToGenerate.addNearPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
offsetPosZ + regionPosZ * size, shouldSort);
}
} else if (!doesDataExist && isFarModeSwitchEdge) {
posToGenerate.addFarPosToGenerate(detailLevel, offsetPosX + regionPosX * size,
offsetPosZ + regionPosZ * size, shouldSort);
} else if (detailLevel > LodUtil.CHUNK_DETAIL_LEVEL) {
for (int x = 0; x <= 1; x++)
for (int z = 0; z <= 1; z++)
getPosToGenerate(posToGenerate, childDetailLevel, childOffsetPosX + x, childOffsetPosZ + z, playerPosX,
playerPosZ, priority, genMode, shouldSort, needFarPos);
} else {
getPosToGenerate(posToGenerate, childDetailLevel, childOffsetPosX, childOffsetPosZ, playerPosX, playerPosZ,
priority, genMode, shouldSort, needFarPos);
}
}
public byte getRenderDetailLevelAt(int playerPosX, int playerPosZ, byte detailLevel, int offsetX, int offsetZ) {
EGenerationPriority generationPriority = getResolvedGenerationPriority();
EDropoffQuality dropoffQuality = CONFIG.client().graphics().quality().getResolvedDropoffQuality();
double minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ,
playerPosX, playerPosZ);
byte targetLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
byte renderLevel;
if (targetLevel > dropoffQuality.fastModeSwitch) {
double centerDistance = LevelPosUtil.centerDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ);
renderLevel = DetailDistanceUtil.getDetailLevelFromDistance(centerDistance);
} else {
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
double posMinDistance = LevelPosUtil.minDistance(detailLevel,
LevelPosUtil.getRegionModule(detailLevel, offsetX) + regionPosX*size,
LevelPosUtil.getRegionModule(detailLevel, offsetZ) + regionPosZ*size,
playerPosX, playerPosZ);
renderLevel = DetailDistanceUtil.getDetailLevelFromDistance(posMinDistance);
}
return (byte) Math.max(getMinDetailLevel(), renderLevel);
}
private EGenerationPriority getResolvedGenerationPriority() {
EGenerationPriority priority = Config.Client.WorldGenerator.generationPriority.get();
IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (priority == EGenerationPriority.AUTO)
priority = MC.hasSinglePlayerServer() ? EGenerationPriority.FAR_FIRST : EGenerationPriority.BALANCED;
return priority;
}
private EDropoffQuality getResolvedDropoffQuality() {
EDropoffQuality dropoffQuality = Config.Client.Graphics.Quality.dropoffQuality.get();
if (dropoffQuality == EDropoffQuality.AUTO)
dropoffQuality = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() < 128 ?
EDropoffQuality.SMOOTH_DROPOFF : EDropoffQuality.PERFORMANCE_FOCUSED;
return dropoffQuality;
}
public static final class LevelPos {
public final byte detail;
public final int posX;
public final int posZ;
LevelPos(byte d, int x, int z) {
detail = d;
posX = x;
posZ = z;
}
}
public Iterator<LevelPos> posToRenderIterator() {
return new Iterator<LevelPos>() {
final byte minDetail = minDetailLevel;
int offsetX = 0;
int offsetZ = 0;
final int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - minDetail);
private void advance() {
}
@Override
public boolean hasNext()
{
return (offsetZ >= size);
}
@Override
public LevelPos next()
{
// TODO Auto-generated method stub
return null;
}
};
}
/**
* Updates all children.
* <p>
* TODO could this be renamed mergeArea?
*/
public void updateArea(byte detailLevel, int posX, int posZ) {
int width;
int startX;
int startZ;
// Update the level lower or equal to the detail level
for (byte down = (byte) (minDetailLevel + 1); down <= detailLevel; down++) {
startX = LevelPosUtil.convert(detailLevel, posX, down);
startZ = LevelPosUtil.convert(detailLevel, posZ, down);
width = 1 << (detailLevel - down);
for (int x = 0; x < width; x++)
for (int z = 0; z < width; z++)
update(down, startX + x, startZ + z);
}
// Update the level higher than the detail level
for (byte up = (byte) (Math.max(detailLevel, minDetailLevel) + 1); up <= LodUtil.REGION_DETAIL_LEVEL; up++) {
update(up, LevelPosUtil.convert(detailLevel, posX, up), LevelPosUtil.convert(detailLevel, posZ, up));
}
needSignalToRegenBuffer = true;
}
public boolean regenerateLodFromArea(byte detailLevel, int posX, int posZ, int widthX, int widthZ) {
if (detailLevel >= LodUtil.REGION_DETAIL_LEVEL) return false;
int modPosX = LevelPosUtil.getRegionModule(detailLevel, posX);
int modPosZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
//ApiShared.LOGGER.info("RegenerateLodFromArea(region:{} level:{}, x:{}, z:{}, wx:{}, wz:{})",
// getRegionPos(), detailLevel, modPosX, modPosZ, widthX, widthZ);
if (detailLevel < minDetailLevel) {
byte startLevel = minDetailLevel;
int maxPosX = Math.floorDiv(modPosX+widthX-1, (1 << (minDetailLevel-startLevel)))+1;
int maxPosZ = Math.floorDiv(modPosZ+widthZ-1, (1 << (minDetailLevel-startLevel)))+1;
modPosX = Math.floorDiv(modPosX, (1 << (minDetailLevel-startLevel)));
modPosZ = Math.floorDiv(modPosZ, (1 << (minDetailLevel-startLevel)));
widthX = maxPosX-modPosX;
widthZ = maxPosZ-modPosZ;
detailLevel = minDetailLevel;
}
do {
int maxPosX = Math.floorDiv(modPosX+widthX-1, 2)+1;
int maxPosZ = Math.floorDiv(modPosZ+widthZ-1, 2)+1;
modPosX = Math.floorDiv(modPosX, 2);
modPosZ = Math.floorDiv(modPosZ, 2);
widthX = maxPosX-modPosX;
widthZ = maxPosZ-modPosZ;
detailLevel++;
// ApiShared.LOGGER.info(" - Shink: (level:{}, x:{}, z:{}, wx:{}, wz:{})", detailLevel, modPosX, modPosZ, widthX, widthZ);
chunkUpdate(detailLevel, modPosX, modPosZ, widthX, widthZ);
} while (detailLevel < LodUtil.REGION_DETAIL_LEVEL);
needSignalToRegenBuffer = true;
return true;
}
/**
* Update the child at the given relative Pos
* <p>
* TODO could this be renamed mergeChildData?
* TODO make this return whether any value has changed
*/
private void update(byte detailLevel, int modPosX, int modPosZ) {
//ApiShared.LOGGER.info(" - Update: (level:{}, subLevel:{}, mx:{}, mz:{})", detailLevel, detailLevel-1, modPosX, modPosZ);
dataContainer[detailLevel].updateData(dataContainer[detailLevel - 1], modPosX, modPosZ);
}
private void chunkUpdate(byte detailLevel, int modPosX, int modPosZ, int widthX,int widthZ) {
for (int ox=0; ox<widthX; ox++) {
for (int oz=0; oz<widthZ; oz++) {
update(detailLevel, modPosX+ox, modPosZ+oz);
}
}
}
/**
* Returns if data exists at the given relative Pos.
*/
public boolean doesDataExist(byte detailLevel, int posX, int posZ, EDistanceGenerationMode requiredMode) {
if (detailLevel < minDetailLevel || dataContainer[detailLevel] == null)
return false;
int modPosX = LevelPosUtil.getRegionModule(detailLevel, posX);
int modPosZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
if (!dataContainer[detailLevel].doesItExist(modPosX, modPosZ)) return false;
if (requiredMode== EDistanceGenerationMode.NONE) return true;
byte mode = getGenerationMode(detailLevel, posX, posZ);
return (mode>=requiredMode.complexity);
}
/**
* Gets the generation mode for the data point at the given relative pos.
*/
public byte getGenerationMode(byte detailLevel, int posX, int posZ) {
int modPosX = LevelPosUtil.getRegionModule(detailLevel, posX);
int modPosZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
if (dataContainer[detailLevel] != null && dataContainer[detailLevel].doesItExist(modPosX, modPosZ))
// We take the bottom information always
// TODO what does that mean? bottom of what?
return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getSingleData(modPosX, modPosZ));
else
throw new RuntimeException("Data does not exist!");
}
/**
* Returns the lowest (least detailed) detail level in this region
*/
public byte getMinDetailLevel() {
return minDetailLevel;
}
/**
* Returns the LevelContainer for the detailLevel
*
* @throws IllegalArgumentException if the detailLevel is less than
* minDetailLevel
*/
public LevelContainer getLevel(byte detailLevel) {
if (detailLevel < minDetailLevel)
throw new IllegalArgumentException("getLevel asked for a detail level that does not exist: minimum: ["
+ minDetailLevel + "] level requested: [" + detailLevel + "]");
return dataContainer[detailLevel];
}
/**
* Add the levelContainer to this Region, updating the minDetailLevel if
* necessary.
*
* @throws IllegalArgumentException if the LevelContainer's detailLevel is 2 or
* more detail levels lower than the
* minDetailLevel of this region.
*/
public void addLevelContainer(LevelContainer levelContainer) {
if (levelContainer.getDetailLevel() < minDetailLevel - 1) {
throw new IllegalArgumentException("the LevelContainer's detailLevel was " + "["
+ levelContainer.getDetailLevel() + "] but this region "
+ "only allows adding LevelContainers with a " + "detail level of [" + (minDetailLevel - 1) + "]");
}
dataContainer[levelContainer.getDetailLevel()] = levelContainer;
if (levelContainer.getDetailLevel() == minDetailLevel - 1)
minDetailLevel = levelContainer.getDetailLevel();
needRecheckGenPoint = true;
}
// TODO James thinks cutTree and growTree (which he renamed to match cutTree)
// should have more descriptive names, to make sure the "Tree" portion isn't
// confused with Minecraft trees (the plant).
/**
* Removes any dataContainers that are higher than the given detailLevel
*/
public void cutTree(byte detailLevel) {
if (detailLevel > minDetailLevel) {
minDetailLevel = detailLevel;
for (byte detailLevelIndex = 0; detailLevelIndex < detailLevel; detailLevelIndex++)
dataContainer[detailLevelIndex] = null;
}
}
/**
* Make this region more detailed to the detailLevel given. TODO is that
* correct?
*/
public void growTree(byte detailLevel) {
if (detailLevel < minDetailLevel) {
for (byte detailLevelIndex = (byte) (minDetailLevel
- 1); detailLevelIndex >= detailLevel; detailLevelIndex--) {
if (dataContainer[detailLevelIndex + 1] == null)
dataContainer[detailLevelIndex + 1] = new VerticalLevelContainer((byte) (detailLevelIndex + 1));
dataContainer[detailLevelIndex] = dataContainer[detailLevelIndex + 1].expand();
}
minDetailLevel = detailLevel;
needRecheckGenPoint = true;
}
}
/**
* return RegionPos of this lod region
*/
public DHRegionPos getRegionPos() {
return new DHRegionPos(regionPosX, regionPosZ);
}
/**
* Returns how many LODs are in this region
*/
public int getNumberOfLods() {
int count = 0;
for (LevelContainer container : dataContainer)
count += container.getMaxNumberOfLods();
return count;
}
public EVerticalQuality getVerticalQuality() {
return verticalQuality;
}
public int getMaxVerticalData(byte detailLevel) {
return dataContainer[detailLevel].getVerticalSize();
}
public LevelContainer[] debugGetDataContainers() {return dataContainer;}
@Override
public String toString() {
return getLevel(LodUtil.REGION_DETAIL_LEVEL).toString();
}
}
@@ -1,467 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.objects.lod;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.objects.LodDataView;
import com.seibel.lod.core.util.*;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
/**
*
* @author Leonardo Amato
* @version ??
*/
public class VerticalLevelContainer implements LevelContainer
{
public static final boolean DO_SAFETY_CHECKS = true;
private final short minHeight;
public final byte detailLevel;
public final int size;
public final int verticalSize;
public final long[] dataContainer;
//Currently, these variable are not used. We are going to use them in the new data format
public final int[] verticalDataContainer = null;
public final int[] colorDataContainer = null;
public final byte[] lightDataContainer = null;
public final short[] positionDataContainer = null;
/*WE PROBABLY ARE GOING TO USE THIS IN THE FUTURE
FOR NOW WE KEEP THE OLD SYSTEM
public final short[] sectionVerticalSize = null;
public final int[][] verticalDataContainer = null;
public final int[][] colorDataContainer = null;
public final byte[][] lightDataContainer = null;
public final short[] positionDataContainer = null;
*/
public VerticalLevelContainer(byte detailLevel)
{
this.detailLevel = detailLevel;
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
verticalSize = DetailDistanceUtil.getMaxVerticalData(detailLevel);
dataContainer = new long[size * size * DetailDistanceUtil.getMaxVerticalData(detailLevel)];
minHeight = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).getWrappedClientWorld().getMinHeight();
}
@Override
public byte getDetailLevel()
{
return detailLevel;
}
@Override
public void clear(int posX, int posZ)
{
for (int verticalIndex = 0; verticalIndex < verticalSize; verticalIndex++)
dataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = DataPointUtil.EMPTY_DATA;
}
@Override
public boolean addData(long data, int posX, int posZ, int verticalIndex)
{
dataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = data;
return true;
}
private void forceWriteVerticalData(long[] data, int posX, int posZ)
{
int index = posX * size * verticalSize + posZ * verticalSize;
if (verticalSize >= 0) System.arraycopy(data, 0, dataContainer, index + 0, verticalSize);
}
@Override
public boolean addVerticalData(long[] data, int posX, int posZ, boolean override)
{
int index = posX * size * verticalSize + posZ * verticalSize;
int compare = DataPointUtil.compareDatapointPriority(data[0], dataContainer[index]);
if (override) {
if (compare<0) return false;
} else {
if (compare<=0) return false;
}
forceWriteVerticalData(data, posX, posZ);
return true;
}
@Override
public boolean copyVerticalData(LodDataView data, int posX, int posZ, boolean override) {
if (DO_SAFETY_CHECKS) {
if (data.size() != verticalSize)
throw new IllegalArgumentException("data size not the same as vertical size");
if (posX < 0 || posX >= size)
throw new IllegalArgumentException("X position is out of bounds");
if (posZ < 0 || posZ >= size)
throw new IllegalArgumentException("Z position is out of bounds");
}
int index = posX * size * verticalSize + posZ * verticalSize;
int compare = DataPointUtil.compareDatapointPriority(data.get(0), dataContainer[index]);
if (override) {
if (compare<0) return false;
} else {
if (compare<=0) return false;
}
data.copyTo(dataContainer, index);
return true;
}
@Override
public boolean addChunkOfData(long[] data, int posX, int posZ, int widthX, int widthZ, boolean override)
{
boolean anyChange = false;
if (posX+widthX > size || posZ+widthZ > size)
throw new IndexOutOfBoundsException("addChunkOfData param not inside valid range");
if (widthX*widthZ*verticalSize != data.length)
throw new IndexOutOfBoundsException("addChunkOfData data array not sized correctly to contain the data to be copied");
if (posX<0 || posZ<0 || widthX<0 || widthZ<0)
throw new IndexOutOfBoundsException("addChunkOfData param is negative");
for (int ox=0; ox<widthX; ox++) {
anyChange = DataPointUtil.mergeTwoDataArray(
dataContainer, ((ox+posX)*size+posZ) * verticalSize,
data, ox*widthX*verticalSize,
widthZ, verticalSize, override);
}
return anyChange;
}
@Override
public boolean copyChunkOfData(LodDataView data, int posX, int posZ, int widthX, int widthZ, boolean override) {
boolean anyChange = false;
if (posX+widthX > size || posZ+widthZ > size)
throw new IndexOutOfBoundsException("addChunkOfData param not inside valid range");
if (widthX*widthZ*verticalSize != data.size())
throw new IndexOutOfBoundsException("addChunkOfData data array not sized correctly to contain the data to be copied");
if (posX<0 || posZ<0 || widthX<0 || widthZ<0)
throw new IndexOutOfBoundsException("addChunkOfData param is negative");
for (int ox=0; ox<widthX; ox++) {
anyChange |= new LodDataView(dataContainer, widthX*verticalSize,
((ox+posX)*size+posZ) * verticalSize)
.mergeWith(data, verticalSize, override);
}
return anyChange;
}
@Override
public long getData(int posX, int posZ, int verticalIndex)
{
return dataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public short getPositionData(int posX, int posZ)
{
return positionDataContainer[posX * size + posZ];
}
public int getVerticalData(int posX, int posZ, int verticalIndex)
{
return verticalDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public int getColorData(int posX, int posZ, int verticalIndex)
{
return colorDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public byte getLightData(int posX, int posZ, int verticalIndex)
{
return lightDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex];
}
public void setPositionData(short positionData, int posX, int posZ)
{
positionDataContainer[posX * size + posZ] = positionData;
}
public void setVerticalData(int verticalData, int posX, int posZ, int verticalIndex)
{
verticalDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = verticalData;
}
public void setColorData(int colorData, int posX, int posZ, int verticalIndex)
{
colorDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = colorData;
}
public void setLightData(byte lightData, int posX, int posZ, int verticalIndex)
{
lightDataContainer[posX * size * verticalSize + posZ * verticalSize + verticalIndex] = lightData;
}
@Override
public long getSingleData(int posX, int posZ)
{
return dataContainer[posX * size * verticalSize + posZ * verticalSize];
}
@Override
public long[] getAllData(int posX, int posZ)
{
long[] result = new long[verticalSize];
int index = posX * size * verticalSize + posZ * verticalSize;
System.arraycopy(dataContainer, index, result, 0, verticalSize);
return result;
}
@Override
public LodDataView getVerticalDataView(int posX, int posZ) {
return new LodDataView(dataContainer, verticalSize, posX * size * verticalSize + posZ * verticalSize);
}
@Override
public int getVerticalSize()
{
return verticalSize;
}
public int getSize()
{
return size;
}
@Override
public boolean doesItExist(int posX, int posZ)
{
return DataPointUtil.doesItExist(getSingleData(posX, posZ));
}
private long[] readDataVersion6(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
int x = size * size * tempMaxVerticalData;
byte[] data = new byte[x * Long.BYTES];
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
inputData.readFully(data);
long[] result = new long[x];
bb.asLongBuffer().get(result);
patchVersion9Reorder(result);
patchHeightAndDepth(result,-minHeight);
return result;
}
private long[] readDataVersion7(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
int x = size * size * tempMaxVerticalData;
byte[] data = new byte[x * Long.BYTES];
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
inputData.readFully(data);
long[] result = new long[x];
bb.asLongBuffer().get(result);
patchVersion9Reorder(result);
patchHeightAndDepth(result, 64 - minHeight);
return result;
}
private long[] readDataVersion8(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
int x = size * size * tempMaxVerticalData;
byte[] data = new byte[x * Long.BYTES];
short tempMinHeight = Short.reverseBytes(inputData.readShort());
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
inputData.readFully(data);
long[] result = new long[x];
bb.asLongBuffer().get(result);
patchVersion9Reorder(result);
if (tempMinHeight != minHeight) {
patchHeightAndDepth(result,tempMinHeight - minHeight);
}
return result;
}
private long[] readDataVersion9(DataInputStream inputData, int tempMaxVerticalData) throws IOException {
int x = size * size * tempMaxVerticalData;
byte[] data = new byte[x * Long.BYTES];
short tempMinHeight = Short.reverseBytes(inputData.readShort());
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
inputData.readFully(data);
long[] result = new long[x];
bb.asLongBuffer().get(result);
if (tempMinHeight != minHeight) {
patchHeightAndDepth(result,tempMinHeight - minHeight);
}
return result;
}
private static void patchHeightAndDepth(long[] data, int offset) {
for (int i=0; i<data.length; i++) {
data[i] = DataPointUtil.shiftHeightAndDepth(data[i], (short)offset);
}
}
private static void patchVersion9Reorder(long[] data) {
for (int i=0; i<data.length; i++) {
data[i] = DataPointUtil.version9Reorder(data[i]);
}
}
public VerticalLevelContainer(DataInputStream inputData, int version, byte expectedDetailLevel) throws IOException {
minHeight = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).getWrappedClientWorld().getMinHeight();
detailLevel = inputData.readByte();
if (detailLevel != expectedDetailLevel)
throw new IOException("Invalid Data: The expected detail level should be "+expectedDetailLevel+
" but the data header say it's "+detailLevel);
size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
int fileMaxVerticalData = inputData.readByte() & 0b01111111;
long[] tempDataContainer = null;
switch (version) {
case 6:
tempDataContainer = readDataVersion6(inputData, fileMaxVerticalData);
break;
case 7:
tempDataContainer = readDataVersion7(inputData, fileMaxVerticalData);
break;
case 8:
tempDataContainer = readDataVersion8(inputData, fileMaxVerticalData);
break;
case 9:
tempDataContainer = readDataVersion9(inputData, fileMaxVerticalData);
break;
default:
assert false;
}
int targetMaxVerticalData = DetailDistanceUtil.getMaxVerticalData(detailLevel);
verticalSize = targetMaxVerticalData;
dataContainer = DataPointUtil.changeMaxVertSize(tempDataContainer, fileMaxVerticalData, verticalSize);
}
@Override
public LevelContainer expand()
{
return new VerticalLevelContainer((byte) (getDetailLevel() - 1));
}
private static final ThreadLocal<long[][]> tLocalVerticalUpdateArrays = ThreadLocal.withInitial(() ->
{
return new long[LodUtil.DETAIL_OPTIONS - 1][];
});
@Override
public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ)
{
//We reset the array
long[][] verticalUpdateArrays = tLocalVerticalUpdateArrays.get();
long[] dataToMerge = verticalUpdateArrays[detailLevel-1];
int arrayLength = DetailDistanceUtil.getMaxVerticalData(detailLevel-1) * 4;
if (dataToMerge == null || dataToMerge.length != arrayLength) {
dataToMerge = new long[arrayLength];
verticalUpdateArrays[detailLevel-1] = dataToMerge;
} else Arrays.fill(dataToMerge, 0);
int lowerMaxVertical = dataToMerge.length / 4;
int childPosX;
int childPosZ;
long[] data;
boolean anyDataExist = false;
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
{
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
if (lowerLevelContainer.doesItExist(childPosX, childPosZ)) anyDataExist = true;
for (int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++)
dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
}
}
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getVerticalSize());
if (!anyDataExist)
throw new RuntimeException("Update data called but no child datapoint exist!");
if ((!DataPointUtil.doesItExist(data[0])) && anyDataExist)
throw new RuntimeException("Update data called but higher level datapoint doesn't exist even though child data does exist!");
//FIXME: Disabled check if genMode for old data is already invalid due to having genMode 0.
if (DataPointUtil.getGenerationMode(data[0]) != DataPointUtil.getGenerationMode(lowerLevelContainer.getSingleData(posX*2, posZ*2)))
throw new RuntimeException("Update data called but higher level datapoint does not have the same GenerationMode as the top left corner child datapoint!");
forceWriteVerticalData(data, posX, posZ);
}
@Override
public boolean writeData(DataOutputStream output) throws IOException {
output.writeByte(detailLevel);
output.writeByte((byte) verticalSize);
output.writeByte((byte) (minHeight & 0xFF));
output.writeByte((byte) ((minHeight >> 8) & 0xFF));
boolean allGenerated = true;
int x = size * size;
for (int i = 0; i < x; i++)
{
for (int j = 0; j < verticalSize; j++)
{
long current = dataContainer[i * verticalSize + j];
output.writeLong(Long.reverseBytes(current));
}
if (!DataPointUtil.doesItExist(dataContainer[i]))
allGenerated = false;
}
return allGenerated;
}
@Override
public String toString()
{
String LINE_DELIMITER = "\n";
String DATA_DELIMITER = " ";
String SUBDATA_DELIMITER = ",";
StringBuilder stringBuilder = new StringBuilder();
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
stringBuilder.append(detailLevel);
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) stringBuilder.append(SUBDATA_DELIMITER);
}
if (x != size) stringBuilder.append(DATA_DELIMITER);
}
if (z != size) stringBuilder.append(LINE_DELIMITER);
}
return stringBuilder.toString();
}
@Override
public int getMaxNumberOfLods()
{
return size * size * getVerticalSize();
}
@Override
public long getRoughRamUsage()
{
return dataContainer.length * Long.BYTES;
}
}
@@ -1,143 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.objects.opengl;
import java.util.ConcurrentModificationException;
import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder;
import com.seibel.lod.core.enums.config.EGpuUploadMethod;
import com.seibel.lod.core.render.LodRenderProgram;
import com.seibel.lod.core.util.StatsMap;
public abstract class RenderBuffer implements AutoCloseable
{
private enum State {
None,
Building,
Uploading,
Closed,
}
private State owner = State.None;
private State nextOwner = State.None;
final private void _lockThread(State newOwner) {
if (owner != State.None || (nextOwner != State.None && nextOwner != newOwner))
throw new ConcurrentModificationException("RenderMethod Illegal state!");
owner = newOwner;
nextOwner = State.None;
}
final private void _unlockThread(State oldOwner) {
if (owner != oldOwner)
throw new ConcurrentModificationException("RenderMethod Illegal state!");
owner = State.None;
}
final private void _unlockThreadTo(State oldOwner, State newOwner) {
if (owner != oldOwner)
throw new ConcurrentModificationException("RenderMethod Illegal state!");
owner = State.None;
nextOwner = newOwner;
}
final public void build(Runnable r) {
_lockThread(State.Building);
try {
r.run();
} finally {
_unlockThread(State.Building);
}
}
/* Return false if current renderMethod is not suited for current builder
* This will auto close the object if returning false. */
final public boolean tryUploadBuffers(LodQuadBuilder builder, EGpuUploadMethod uploadMethod) {
_lockThread(State.Uploading);
boolean successful = false;
try {
successful = uploadBuffers(builder, uploadMethod);
return successful;
} finally {
if (!successful) {
_unlockThreadTo(State.Uploading, State.Closed);
close();
} else {
_unlockThread(State.Uploading);
}
}
}
// ======================================================================
// ====================== Methods for implementations ===================
// ======================================================================
// =========== Called by build starter thread ==========
/* Called on being reused after the object is swapped to the back
* and a new build event is triggered. Used for cleaning up non
* reusable objects sooner.
* Note: This is run on BUILDER thread, and does not have access to
* GL Context, Use GLProxy.recordOpenGlCall() to access GL Context
* instead! */
public void onReuse() {}
// =========== Called by buffer upload thread ==========
/* Return false if current renderMethod is not suited for current builder
* If false, close call will be automatically triggered.
* If true, the object will be used (by first calling the swapBufferToFront())
* on tick render. */
protected abstract boolean uploadBuffers(LodQuadBuilder builder, EGpuUploadMethod uploadMethod);
// ========== Called by render thread ==========
/* Called on buffer first being used by a render thread. */
public void onSwapToFront() {}
/* Called on buffer no longer being used. (Life ended)
* Return false if current object cannot be reused.
* Note: This should not do too much stuff as it is run on render thread!
* The corresponding cleanups should be done using the onReuse() to prevent
* lag spikes! If you want this buffer to not be reused, but cleanup is
* expensive, use onReuse() instead!
* Note 2: This may not be triggered on some situations like renderer being
* terminated, or dimension changed. So implementation should NEVER assume
* that onSwapToFront() will link to a call of onSwapToBack()! */
public boolean onSwapToBack() {return true;}
/* Called on... well... rendering.
* Return false if nothing rendered. (Optional) */
public abstract boolean render(LodRenderProgram shaderProgram);
// ========== Called by any thread. (thread safe) ==========
/* Called by anyone. This method is allowed to throw exceptions, but
* are never allowed to modify any values. This should behave the same
* to other methods as if the method have never been called.
* Note: This method is PURELY for debug or stats logging ONLY! */
public abstract void debugDumpStats(StatsMap statsMap);
// ========= Called only when 1 thread is using it =======
/* This method is called when object is no longer in use.
* Called either after uploadBuffers() returned false (On buffer Upload
* thread), or by others when the object is not being used. (not in build,
* upload, or render state). */
public abstract void close();
}
@@ -1,65 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.function.Consumer;
public final class ComsumerOutputStream extends OutputStream
{
final Consumer<String> func;
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public ComsumerOutputStream(Consumer<String> func) {
this.func = func;
}
@Override
public void write(int b)
{
buffer.write(b);
}
@Override
public void write(byte[] b) throws IOException {
buffer.write(b);
}
@Override
public void write(byte[] b,
int off,
int len) {
buffer.write(b, off, len);
}
@Override
public void flush()
{
String str = buffer.toString();
buffer.reset();
func.accept(str);
}
@Override
public void close() throws IOException
{
buffer.close();
}
}
@@ -1,708 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.util;
import com.seibel.lod.core.logging.SpamReducedLogger;
import java.util.Arrays;
/**
*
* @author Leonardo Amato
* @version ??
*/
public class DataPointUtil
{
/*
|_ |g |g |g |a |a |a |a |
|r |r |r |r |r |r |r |r |
|g |g |g |g |g |g |g |g |
|b |b |b |b |b |b |b |b |
|h |h |h |h |h |h |h |h |
|h |h |h |h |d |d |d |d |
|d |d |d |d |d |d |d |d |
|bl |bl |bl |bl |sl |sl |sl |sl |
*/
// Reminder: bytes have range of [-128, 127].
// When converting to or from an int a 128 should be added or removed.
// If there is a bug with color then it's probably caused by this.
public final static int EMPTY_DATA = 0;
public final static int MAX_WORLD_Y_SIZE = 4096;
public final static int ALPHA_DOWNSIZE_SHIFT = 4;
public final static int GEN_TYPE_SHIFT = 60;
public final static int COLOR_SHIFT = 32;
public final static int BLUE_SHIFT = COLOR_SHIFT;
public final static int GREEN_SHIFT = BLUE_SHIFT + 8;
public final static int RED_SHIFT = GREEN_SHIFT + 8;
public final static int ALPHA_SHIFT = RED_SHIFT + 8;
public final static int HEIGHT_SHIFT = 20;
public final static int DEPTH_SHIFT = 8;
public final static int BLOCK_LIGHT_SHIFT = 4;
public final static int SKY_LIGHT_SHIFT = 0;
public final static long ALPHA_MASK = 0xF;
public final static long RED_MASK = 0xFF;
public final static long GREEN_MASK = 0xFF;
public final static long BLUE_MASK = 0xFF;
public final static long COLOR_MASK = 0xFFFFFF;
public final static long HEIGHT_MASK = 0xFFF;
public final static long DEPTH_MASK = 0xFFF;
public final static long HEIGHT_DEPTH_MASK = 0xFFFFFF;
public final static long BLOCK_LIGHT_MASK = 0xF;
public final static long SKY_LIGHT_MASK = 0xF;
public final static long GEN_TYPE_MASK = 0b111;
public final static long COMPARE_SHIFT = GEN_TYPE_SHIFT;
public final static long HEIGHT_SHIFTED_MASK = HEIGHT_MASK << HEIGHT_SHIFT;
public final static long DEPTH_SHIFTED_MASK = DEPTH_MASK << DEPTH_SHIFT;
public final static long VOID_SETTER = HEIGHT_SHIFTED_MASK | DEPTH_SHIFTED_MASK;
public static long createVoidDataPoint(byte generationMode)
{
if (generationMode == 0)
throw new IllegalArgumentException("Trying to create void datapoint with genMode 0, which is NOT allowed in DataPoint version 10!");
return (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT;
}
public static long createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode)
{
return createDataPoint(
ColorUtil.getAlpha(color),
ColorUtil.getRed(color),
ColorUtil.getGreen(color),
ColorUtil.getBlue(color),
height, depth, lightSky, lightBlock, generationMode);
}
public static long createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode)
{
if (generationMode == 0)
throw new IllegalArgumentException("Trying to create datapoint with genMode 0, which is NOT allowed in DataPoint version 10!");
if (height < 0 || height > 4096)
throw new IllegalArgumentException("Height must be between 0 and 4096!");
if (depth < 0 || depth > 4096)
throw new IllegalArgumentException("Depth must be between 0 and 4096!");
if (lightSky < 0 || lightSky > 15)
throw new IllegalArgumentException("Sky light must be between 0 and 15!");
if (lightBlock < 0 || lightBlock > 15)
throw new IllegalArgumentException("Block light must be between 0 and 15!");
if (alpha < 0 || alpha > 255)
throw new IllegalArgumentException("Alpha must be between 0 and 255!");
if (red < 0 || red > 255)
throw new IllegalArgumentException("Red must be between 0 and 255!");
if (green < 0 || green > 255)
throw new IllegalArgumentException("Green must be between 0 and 255!");
if (blue < 0 || blue > 255)
throw new IllegalArgumentException("Blue must be between 0 and 255!");
if (generationMode < 0 || generationMode > 7)
throw new IllegalArgumentException("Generation mode must be between 0 and 7!");
if (depth > height)
throw new IllegalArgumentException("Depth must be less than or equal to height!");
return (long) (alpha >>> ALPHA_DOWNSIZE_SHIFT) << ALPHA_SHIFT
| (red & RED_MASK) << RED_SHIFT
| (green & GREEN_MASK) << GREEN_SHIFT
| (blue & BLUE_MASK) << BLUE_SHIFT
| (height & HEIGHT_MASK) << HEIGHT_SHIFT
| (depth & DEPTH_MASK) << DEPTH_SHIFT
| (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT
| (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT
| (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT
;
}
public static long shiftHeightAndDepth(long dataPoint, short offset) {
long height = (dataPoint + ((long) offset << HEIGHT_SHIFT)) & HEIGHT_SHIFTED_MASK;
long depth = (dataPoint + (offset << DEPTH_SHIFT)) & DEPTH_SHIFTED_MASK;
return dataPoint & ~(HEIGHT_SHIFTED_MASK | DEPTH_SHIFTED_MASK) | height | depth;
}
public static long version9Reorder(long dataPoint) {
/*
|a |a |a |a |r |r |r |r |
|r |r |r |r |g |g |g |g |
|g |g |g |g |b |b |b |b |
|b |b |b |b |h |h |h |h |
|h |h |h |h |h |h |d |d |
|d |d |d |d |d |d |d |d |
|bl |bl |bl |bl |sl |sl |sl |sl |
|l |l |f |g |g |g |v |e |
*/
if ((dataPoint & 1) == 0) return 0;
long height = (dataPoint >>> 26) & 0x3FF;
long depth = (dataPoint >>> 16) & 0x3FF;
if (height == depth || (dataPoint & 0b10)==0b10) {
return createVoidDataPoint((byte) (((dataPoint >>> 2) & 0b111) + 1));
}
return ((dataPoint >>> 60) & 0xF) << ALPHA_SHIFT
| ((dataPoint >>> 52) & 0xFF) << RED_SHIFT
| ((dataPoint >>> 44) & 0xFF) << GREEN_SHIFT
| ((dataPoint >>> 36) & 0xFF) << BLUE_SHIFT
| ((dataPoint >>> 26) & 0x3FF) << HEIGHT_SHIFT
| ((dataPoint >>> 16) & 0x3FF) << DEPTH_SHIFT
| ((dataPoint >>> 8) & 0xFF) << SKY_LIGHT_SHIFT
| (((dataPoint >>> 2) & 0xFF) + 1) << GEN_TYPE_SHIFT;
}
public static short getHeight(long dataPoint)
{
return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(long dataPoint)
{
return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK);
}
public static short getAlpha(long dataPoint)
{
return (short) ((((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT) | 0b1111);
}
public static short getRed(long dataPoint)
{
return (short) ((dataPoint >>> RED_SHIFT) & RED_MASK);
}
public static short getGreen(long dataPoint)
{
return (short) ((dataPoint >>> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(long dataPoint)
{
return (short) ((dataPoint >>> BLUE_SHIFT) & BLUE_MASK);
}
public static byte getLightSky(long dataPoint)
{
return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK);
}
public static byte getLightBlock(long dataPoint)
{
return (byte) ((dataPoint >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK);
}
private static final SpamReducedLogger warnLogger = new SpamReducedLogger(1);
public static byte getGenerationMode(long dataPoint)
{
byte genMode = (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
if (warnLogger.canMaybeLog() && doesItExist(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;
}
return genMode == 0 ? 1 : genMode;
}
public static boolean isVoid(long dataPoint)
{
return (((dataPoint >>> DEPTH_SHIFT) & HEIGHT_DEPTH_MASK) == 0);
}
public static boolean doesItExist(long dataPoint)
{
return dataPoint!=0;
}
public static int getColor(long dataPoint)
{
long alpha = getAlpha(dataPoint);
return (int) (((dataPoint >>> COLOR_SHIFT) & COLOR_MASK) | (alpha << (ALPHA_SHIFT-COLOR_SHIFT)));
}
/** This is used to convert a dataPoint to string (useful for the print function) */
@SuppressWarnings("unused")
public static String toString(long dataPoint)
{
return getHeight(dataPoint) + " " +
getDepth(dataPoint) + " " +
getAlpha(dataPoint) + " " +
getRed(dataPoint) + " " +
getBlue(dataPoint) + " " +
getGreen(dataPoint) + " " +
getLightBlock(dataPoint) + " " +
getLightSky(dataPoint) + " " +
getGenerationMode(dataPoint) + " " +
isVoid(dataPoint) + " " +
doesItExist(dataPoint) + '\n';
}
public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize)
{
start *= packetSize;
length *= packetSize;
arraySize *= packetSize;
//remove comment to not leave garbage at the end
//array[start + packetSize + i] = 0;
if (arraySize - start >= 0) System.arraycopy(array, start + length, array, start, arraySize - start);
}
public static void extendArray(short[] array, int packetSize, int start, int length, int arraySize)
{
start *= packetSize;
length *= packetSize;
arraySize *= packetSize;
for (int i = arraySize - start - 1; i >= 0; i--)
{
array[start + length + i] = array[start + i];
array[start + i] = 0;
}
}
/** Return (>0) if dataA should replace dataB, (0) if equal, (<0) if dataB should replace dataA */
public static int compareDatapointPriority(long dataA, long dataB) {
return (int) ((dataA >> COMPARE_SHIFT) - (dataB >> COMPARE_SHIFT));
}
// Merge the newData data into the target data by comparing the Datapoint Priority.
// If target and newData are same priority, it will use the target one.
// If target and newData size are different, it will copy up to the smallest one.
// Return whether anything changed
public static boolean mergeTwoDataArray(long[] target, long[] newData, int verticalDataSize) {
boolean anyChange = false;
for (int i=0; i<target.length&&i<newData.length; i+=verticalDataSize) {
if (compareDatapointPriority(newData[i], target[i])>0) {
anyChange = true;
System.arraycopy(newData, i, target, i, verticalDataSize);
}
}
return anyChange;
}
// Same as above, but with args for buffer offset.
// Return whether anything changed
public static boolean mergeTwoDataArray(long[] target, int targetOffset, long[] newData, int newDataOffset, int dataLength, int verticalDataSize, boolean override) {
if (targetOffset + verticalDataSize*dataLength>target.length)
throw new ArrayIndexOutOfBoundsException("\"target\" array index out of bounds");
if (newDataOffset + verticalDataSize*dataLength>newData.length)
throw new ArrayIndexOutOfBoundsException("\"newData\" array index out of bounds");
boolean anyChange = false;
for (int o=0; o<(dataLength*verticalDataSize); o+=verticalDataSize) {
if (override) {
if (compareDatapointPriority(newData[o+newDataOffset], target[o+targetOffset])>=0) {
anyChange = true;
System.arraycopy(newData, o+newDataOffset, target, o+targetOffset, verticalDataSize);
}
} else {
if (compareDatapointPriority(newData[o+newDataOffset], target[o+targetOffset])>0) {
anyChange = true;
System.arraycopy(newData, o+newDataOffset, target, o+targetOffset, verticalDataSize);
}
}
}
return anyChange;
}
// Extract a section of data from the 2D data array
public static long[] extractDataArray(long[] source, int inWidth, int inHeight, int outX, int outY, int outWidth, int outHeight) {
int dataSetSize = source.length/inWidth/inHeight;
if (dataSetSize*inWidth*inHeight != source.length)
throw new ArrayIndexOutOfBoundsException("\"source\" array invalid width and height");
if (outWidth > inWidth || outX + outWidth > inWidth)
throw new ArrayIndexOutOfBoundsException("X index out of bounds");
if (outHeight > inHeight || outY + outHeight > inHeight)
throw new ArrayIndexOutOfBoundsException("Y index out of bounds");
long[] out = new long[dataSetSize*outWidth*outHeight];
for (int x=0; x<outWidth; x++) {
System.arraycopy(source, ((outX+x)*inHeight+outY)*dataSetSize,
out, (x*outHeight)*dataSetSize,
outHeight*dataSetSize);
}
return out;
}
// Extract a section of data from the 2D data array
// WARN: if sourceVertSize == targetVertSize, it will return the source array!!! Be careful about this!
public static long[] changeMaxVertSize(long[] source, int sourceVertSize, int targetVertSize) {
if (source.length%sourceVertSize != 0)
throw new ArrayIndexOutOfBoundsException("\"source\" array invalid vertical size or length");
if (sourceVertSize == targetVertSize) return source;
if (sourceVertSize > targetVertSize) {
int size = source.length/sourceVertSize;
long[] dataToMerge = new long[sourceVertSize];
long[] newData = new long[size * targetVertSize];
for (int i = 0; i < size; i++)
{
System.arraycopy(source, i * sourceVertSize, dataToMerge, 0, sourceVertSize);
long[] tempBuffer = DataPointUtil.mergeMultiData(dataToMerge, sourceVertSize, targetVertSize);
System.arraycopy(tempBuffer, 0, newData, i * targetVertSize, targetVertSize);
}
return newData;
} else {
int size = source.length/sourceVertSize;
long[] newData = new long[size * targetVertSize];
for (int i = 0; i < size; i++) {
System.arraycopy(source, i * sourceVertSize, newData, i * targetVertSize, sourceVertSize);
}
return newData;
}
}
private static final ThreadLocal<short[]> tLocalHeightAndDepth = new ThreadLocal<short[]>();
private static final ThreadLocal<int[]> tDataIndexCache = new ThreadLocal<int[]>();
private static final ThreadLocal<long[]> tMaxVerticalData = new ThreadLocal<long[]>();
/**
* This method merge column of multiple data together
* @param dataToMerge one or more columns of data
* @param inputVerticalData vertical size of an input data
* @param maxVerticalData max vertical size of the merged data
* @return one column of correctly parsed data
*/
// TODO: Make this operate on a out param array, to allow skipping copy array on use
public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData)
{
//size indicate how many position we are merging in one position
int size = dataToMerge.length / inputVerticalData;
// We initialize the arrays that are going to be used
int heightAndDepthLength = (MAX_WORLD_Y_SIZE / 2 + 16) * 2;
short[] heightAndDepth = tLocalHeightAndDepth.get();
if (heightAndDepth==null || heightAndDepth.length != heightAndDepthLength) {
heightAndDepth = new short[heightAndDepthLength];
tLocalHeightAndDepth.set(heightAndDepth);
}
int dataPointLength = maxVerticalData;
long[] dataPoint = tMaxVerticalData.get();
if (dataPoint==null || dataPoint.length != dataPointLength) {
dataPoint = new long[dataPointLength];
tMaxVerticalData.set(dataPoint);
} else Arrays.fill(dataPoint, 0);
byte genMode = getGenerationMode(dataToMerge[0]);
if (genMode == 0) genMode = 1; // FIXME: Hack to make the version 10 genMode never be 0.
boolean allEmpty = true;
boolean allVoid = true;
boolean limited = false;
boolean allDefault;
long singleData;
short depth;
short height;
int count = 0;
int i;
int ii;
int dataIndex;
//We collect the indexes of the data, ordered by the depth
for (int index = 0; index < size; index++)
{
if (index == 0)
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[dataIndex];
if (doesItExist(singleData))
{
//genMode = Math.min(genMode, getGenerationMode(singleData));
allEmpty = false;
if (!isVoid(singleData))
{
allVoid = false;
count++;
heightAndDepth[dataIndex * 2] = getHeight(singleData);
heightAndDepth[dataIndex * 2 +1] = getDepth(singleData);
}
}
else
break;
}
}
else
{
for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++)
{
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (doesItExist(singleData))
{
//genMode = Math.min(genMode, getGenerationMode(singleData));
allEmpty = false;
if (!isVoid(singleData))
{
allVoid = false;
depth = getDepth(singleData);
height = getHeight(singleData);
int botPos = -1;
int topPos = -1;
//values fall in between and possibly require extension of array
boolean botExtend = false;
boolean topExtend = false;
for (i = 0; i < count; i++)
{
if (depth < heightAndDepth[i * 2] && depth >= heightAndDepth[i * 2 + 1])
{
botPos = i;
break;
}
else if (depth < heightAndDepth[i * 2 + 1] && ((i + 1 < count && depth >= heightAndDepth[(i + 1) * 2]) || i + 1 == count))
{
botPos = i;
botExtend = true;
break;
}
}
for (i = 0; i < count; i++)
{
if (height <= heightAndDepth[i * 2] && height > heightAndDepth[i * 2 + 1])
{
topPos = i;
break;
}
else if (height <= heightAndDepth[i * 2 + 1] && ((i + 1 < count && height > heightAndDepth[(i + 1) * 2]) || i + 1 == count))
{
topPos = i;
topExtend = true;
break;
}
}
if (topPos == -1)
{
if (botPos == -1)
{
//whole block falls above
extendArray(heightAndDepth, 2, 0, 1, count);
heightAndDepth[0] = height;
heightAndDepth[1] = depth;
count++;
}
else if (!botExtend)
{
//only top falls above extending it there, while bottom is inside existing
shrinkArray(heightAndDepth, 2, 0, botPos, count);
heightAndDepth[0] = height;
count -= botPos;
}
else
{
//top falls between some blocks, extending those as well
shrinkArray(heightAndDepth, 2, 0, botPos, count);
heightAndDepth[0] = height;
heightAndDepth[1] = depth;
count -= botPos;
}
}
else if (!topExtend)
{
if (!botExtend)
//both top and bottom are within some exiting blocks, possibly merging them
heightAndDepth[topPos * 2 + 1] = heightAndDepth[botPos * 2 + 1];
else
//top falls between some blocks, extending it there
heightAndDepth[topPos * 2 + 1] = depth;
shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
}
else
{
if (!botExtend)
{
//only top is within some exiting block, extending it
topPos++; //to make it easier
heightAndDepth[topPos * 2] = height;
heightAndDepth[topPos * 2 + 1] = heightAndDepth[botPos * 2 + 1];
shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
}
else
{
//both top and bottom are outside existing blocks
shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count);
count -= botPos - topPos;
extendArray(heightAndDepth, 2, topPos + 1, 1, count);
count++;
heightAndDepth[topPos * 2 + 2] = height;
heightAndDepth[topPos * 2 + 3] = depth;
}
}
}
}
else
break;
}
}
}
//We check if there is any data that's not empty or void
if (allEmpty)
return dataPoint;
if (allVoid)
{
dataPoint[0] = createVoidDataPoint(genMode);
return dataPoint;
}
//we limit the vertical portion to maxVerticalData
int j = 0;
while (count > maxVerticalData)
{
limited = true;
ii = MAX_WORLD_Y_SIZE;
for (i = 0; i < count - 1; i++)
{
if (heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2] <= ii)
{
ii = heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2];
j = i;
}
}
heightAndDepth[j * 2 + 1] = heightAndDepth[(j + 1) * 2 + 1];
for (i = j + 1; i < count - 1; i++)
{
heightAndDepth[i * 2] = heightAndDepth[(i + 1) * 2];
heightAndDepth[i * 2 + 1] = heightAndDepth[(i + 1) * 2 + 1];
}
//System.arraycopy(heightAndDepth, j + 1, heightAndDepth, j, count - j - 1);
count--;
}
//As standard the vertical lods are ordered from top to bottom
if (!limited && size == 1)
{
for (j = 0; j < count; j++)
dataPoint[j] = dataToMerge[j];
}
else
{
//We want to efficiently memorize indexes
int[] dataIndexesCache = tDataIndexCache.get();
if (dataIndexesCache==null || dataIndexesCache.length != size) {
dataIndexesCache = new int[size];
tDataIndexCache.set(dataIndexesCache);
}
Arrays.fill(dataIndexesCache,0);
//For each lod height-depth value we have found we now want to generate the rest of the data
//by merging all lods at lower level that are contained inside the new ones
for (j = 0; j < count; j++)
{
//We firstly collect height and depth data
//this will be added to each realtive long DataPoint
height = heightAndDepth[j * 2];
depth = heightAndDepth[j * 2 + 1];
//if both height and depth are at 0 then we finished
if ((depth == 0 && height == 0) || j >= heightAndDepth.length / 2)
break;
//We initialize data useful for the merge
int numberOfChildren = 0;
allEmpty = true;
allVoid = true;
//We initialize all the new values that we are going to put in the dataPoint
int tempAlpha = 0;
int tempRed = 0;
int tempGreen = 0;
int tempBlue = 0;
int tempLightBlock = 0;
int tempLightSky = 0;
long data = 0;
//For each position that we want to merge
for (int index = 0; index < size; index++)
{
//we scan the lods in the position from top to bottom
while(dataIndexesCache[index] < inputVerticalData)
{
singleData = dataToMerge[index * inputVerticalData + dataIndexesCache[index]];
if (doesItExist(singleData) && !isVoid(singleData))
{
dataIndexesCache[index]++;
if ((depth <= getDepth(singleData) && getDepth(singleData) < height)
|| (depth < getHeight(singleData) && getHeight(singleData) <= height))
{
data = singleData;
break;
}
}
else
break;
}
if (!doesItExist(data))
{
data = createVoidDataPoint(genMode);
}
if (doesItExist(data))
{
allEmpty = false;
if (!isVoid(data))
{
numberOfChildren++;
allVoid = false;
tempAlpha = Math.max(getAlpha(data),tempAlpha);
tempRed += getRed(data) * getRed(data);
tempGreen += getGreen(data) * getGreen(data);
tempBlue += getBlue(data) * getBlue(data);
tempLightBlock += getLightBlock(data);
tempLightSky += getLightSky(data);
}
}
}
if (allEmpty)
//no child has been initialized
dataPoint[j] = EMPTY_DATA;
else if (allVoid)
//all the children are void
dataPoint[j] = createVoidDataPoint(genMode);
else
{
//we have at least 1 child
if (size != 1)
{
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
}
//data = createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault);
//if (j > 0 && getColor(data) == getColor(dataPoint[j]))
//{
// add simplification at the end due to color
//}
dataPoint[j] = createDataPoint(tempAlpha, (int) Math.sqrt(tempRed), (int) Math.sqrt(tempGreen), (int) Math.sqrt(tempBlue), height, depth, tempLightSky, tempLightBlock, genMode);
}
}
}
return dataPoint;
}
}
@@ -27,6 +27,7 @@ import com.seibel.lod.core.enums.config.EHorizontalQuality;
* @author Leonardo Amato * @author Leonardo Amato
* @version ?? * @version ??
*/ */
@Deprecated
public class DetailDistanceUtil public class DetailDistanceUtil
{ {
private static byte minDetail = Config.Client.Graphics.Quality.drawResolution.get().detailLevel; private static byte minDetail = Config.Client.Graphics.Quality.drawResolution.get().detailLevel;
@@ -8,7 +8,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
public class EventLoop implements AutoCloseable { //FIXME This should have close. We are leaking stuff. public class EventLoop implements AutoCloseable {
private final boolean PAUSE_ON_ERROR = ModInfo.IS_DEV_BUILD; private final boolean PAUSE_ON_ERROR = ModInfo.IS_DEV_BUILD;
private final Logger logger = DhLoggerBuilder.getLogger(); private final Logger logger = DhLoggerBuilder.getLogger();
private final ExecutorService executorService; private final ExecutorService executorService;
@@ -24,6 +24,7 @@ package com.seibel.lod.core.util;
* @author Leonardo Amato * @author Leonardo Amato
* @version ?? * @version ??
*/ */
@Deprecated // Use DhSectionPos & DhLodPos & etc classes methods instead
public class LevelPosUtil public class LevelPosUtil
{ {
public static int[] convert(int[] levelPos, byte newDetailLevel) public static int[] convert(int[] levelPos, byte newDetailLevel)
@@ -19,12 +19,10 @@
package com.seibel.lod.core.util; package com.seibel.lod.core.util;
import java.io.File;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import com.seibel.lod.core.a7.util.UncheckedInterruptedException;
import com.seibel.lod.core.config.Config; import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.enums.config.EServerFolderNameMode; import com.seibel.lod.core.enums.config.EServerFolderNameMode;
import com.seibel.lod.core.enums.config.EVanillaOverdraw; import com.seibel.lod.core.enums.config.EVanillaOverdraw;
@@ -33,7 +31,6 @@ import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.objects.ParsedIp; import com.seibel.lod.core.objects.ParsedIp;
import com.seibel.lod.core.objects.Pos2D; import com.seibel.lod.core.objects.Pos2D;
import com.seibel.lod.core.objects.DHRegionPos;
import com.seibel.lod.core.objects.opengl.DefaultLodVertexFormats; import com.seibel.lod.core.objects.opengl.DefaultLodVertexFormats;
import com.seibel.lod.core.objects.opengl.LodVertexFormat; import com.seibel.lod.core.objects.opengl.LodVertexFormat;
import com.seibel.lod.core.util.gridList.EdgeDistanceBooleanGrid; import com.seibel.lod.core.util.gridList.EdgeDistanceBooleanGrid;
@@ -41,9 +38,7 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.Message;
/** /**
* This class holds methods and constants that may be used in multiple places. * This class holds methods and constants that may be used in multiple places.
@@ -183,15 +178,7 @@ public class LodUtil
return returnWorld; return returnWorld;
} }
/** Convert a 2D absolute position into a quad tree relative position. */
public static DHRegionPos convertGenericPosToRegionPos(int x, int z, int detailLevel)
{
int relativePosX = Math.floorDiv(x, 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel));
int relativePosZ = Math.floorDiv(z, 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel));
return new DHRegionPos(relativePosX, relativePosZ);
}
/** returns the server name, IP and game version. */ /** returns the server name, IP and game version. */
@Deprecated // FIXME: There are soooo many duplicated methods doing the same thing everywhere @Deprecated // FIXME: There are soooo many duplicated methods doing the same thing everywhere
@@ -1,304 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.util.gridList;
import java.util.ArrayList;
import java.util.function.Consumer;
/*Layout:
* 0,1,2,
* 3,4,5,
* 6,7,8
*/
@Deprecated // Replace with PosArrayGridList<T>
public class MovableCenteredGridList<T> extends ArrayList<T> {
private int centerX;
private int centerY;
public final int gridCentreToEdge;
public final int gridSize;
/*
* WARNING: Not yet tested if its atomic. (non Thread safe)
*/
public MovableCenteredGridList(MovableCenteredGridList<T> other) {
super(other);
centerX = other.centerX;
centerY = other.centerY;
gridCentreToEdge = other.gridCentreToEdge;
gridSize = other.gridSize;
}
public MovableCenteredGridList(int gridCentreToEdge, int centerX, int centerY) {
super((gridCentreToEdge * 2 + 1) * (gridCentreToEdge * 2 + 1));
gridSize = gridCentreToEdge * 2 + 1;
this.gridCentreToEdge = gridCentreToEdge;
this.centerX = centerX;
this.centerY = centerY;
clear();
}
@Override
public void clear() {
super.clear();
super.ensureCapacity(gridSize*gridSize);
for (int i=0; i<gridSize*gridSize; i++) {
super.add(null);
}
}
public void clear(Consumer<? super T> d) {
super.forEach((t) -> {
if (t!=null) d.accept(t);
});
super.clear();
super.ensureCapacity(gridSize*gridSize);
for (int i=0; i<gridSize*gridSize; i++) {
super.add(null);
}
}
public int getCenterX() {return centerX;}
public int getCenterY() {return centerY;}
// return null if x,y is outside of the grid
public T get(int x, int y) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return _getDirect(x,y);
}
// return false if x,y is outside of the grid
public boolean set(int x, int y, T t) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return _setDirect(x,y, t);
}
// return null if x,y is outside of the grid
// Otherwise, return the new value (for chaining)
public T setAndGet(int x, int y, T t) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return _setDirect(x,y, t) ? t : null;
}
// return null if x,y is outside of the grid
// Otherwise, return the old value
public T swap(int x, int y, T t) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return _swapDirect(x,y, t);
}
public boolean inRange(int x, int y) {
x = x-centerX+gridCentreToEdge;
y = y-centerY+gridCentreToEdge;
return (x>=0 && x<gridSize && y>=0 && y<gridSize);
}
private T _getDirect(int x, int y) {
if (x<0 || x>=gridSize || y<0 || y>=gridSize) return null;
return super.get(x + y * gridSize);
}
private boolean _setDirect(int x, int y, T t) {
if (x<0 || x>=gridSize || y<0 || y>=gridSize) return false;
super.set(x + y * gridSize, t);
return true;
}
private T _swapDirect(int x, int y, T t) {
if (x<0 || x>=gridSize || y<0 || y>=gridSize) return null;
return super.set(x + y * gridSize, t);
}
// Return false if haven't changed. Return true if it did
public boolean move(int newCenterX, int newCenterY) {
if (centerX == newCenterX && centerY == newCenterY) return false;
int deltaX = newCenterX - centerX;
int deltaY = newCenterY - centerY;
// if the x or z offset is equal to or greater than
// the total width, just delete the current data
// and update the centerX and/or centerZ
if (Math.abs(deltaX) >= gridSize || Math.abs(deltaY) >= gridSize)
{
clear();
// update the new center
centerX = newCenterX;
centerY = newCenterY;
return true;
}
centerX = newCenterX;
centerY = newCenterY;
// X
if (deltaX >= 0 && deltaY >= 0)
{
// move everything over to the left-up (as the center moves to the right-down)
for (int x = 0; x < gridSize; x++)
{
for (int y = 0; y < gridSize; y++)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
else if (deltaX < 0 && deltaY >= 0)
{
// move everything over to the right-up (as the center moves to the left-down)
for (int x = gridSize - 1; x >= 0; x--)
{
for (int y = 0; y < gridSize; y++)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
else if (deltaX >= 0 && deltaY < 0)
{
// move everything over to the left-down (as the center moves to the right-up)
for (int x = 0; x < gridSize; x++)
{
for (int y = gridSize - 1; y >= 0; y--)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
else //if (deltaX < 0 && deltaY < 0)
{
// move everything over to the right-down (as the center moves to the left-up)
for (int x = gridSize - 1; x >= 0; x--)
{
for (int y = gridSize - 1; y >= 0; y--)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
return true;
}
public boolean move(int newCenterX, int newCenterY, Consumer<? super T> d) {
if (centerX == newCenterX && centerY == newCenterY) return false;
int deltaX = newCenterX - centerX;
int deltaY = newCenterY - centerY;
// if the x or z offset is equal to or greater than
// the total width, just delete the current data
// and update the centerX and/or centerZ
if (Math.abs(deltaX) >= gridSize || Math.abs(deltaY) >= gridSize)
{
clear(d);
// update the new center
centerX = newCenterX;
centerY = newCenterY;
return true;
}
centerX = newCenterX;
centerY = newCenterY;
// Dealloc stuff
for (int x=0; x<gridSize; x++) {
for (int y=0; y<gridSize; y++) {
if (x-deltaX<0 || y-deltaY<0 ||
x-deltaX>=gridSize || y-deltaY>=gridSize) {
T t = _getDirect(x,y);
if (t!=null) d.accept(t);
}
}
}
// X
if (deltaX >= 0 && deltaY >= 0)
{
// move everything over to the left-up (as the center moves to the right-down)
for (int x = 0; x < gridSize; x++)
{
for (int y = 0; y < gridSize; y++)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
else if (deltaX < 0 && deltaY >= 0)
{
// move everything over to the right-up (as the center moves to the left-down)
for (int x = gridSize - 1; x >= 0; x--)
{
for (int y = 0; y < gridSize; y++)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
else if (deltaX >= 0 && deltaY < 0)
{
// move everything over to the left-down (as the center moves to the right-up)
for (int x = 0; x < gridSize; x++)
{
for (int y = gridSize - 1; y >= 0; y--)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
else //if (deltaX < 0 && deltaY < 0)
{
// move everything over to the right-down (as the center moves to the left-up)
for (int x = gridSize - 1; x >= 0; x--)
{
for (int y = gridSize - 1; y >= 0; y--)
{
_setDirect(x, y, _getDirect(x+deltaX, y+deltaY));
}
}
}
return true;
}
// TODO: This is unused but may be useful later on.
/*
public final MovableGridList<T> subGrid(int gridCentreToEdge, int newCenterX, int newCenterY) {
}*/
@Override
public String toString() {
return "MovableGridList[" + centerX + "," + centerY + "] " + gridSize + "*" + gridSize + "[" + size() + "]";
}
public String toDetailString() {
StringBuilder str = new StringBuilder("\n");
int i = 0;
str.append(this);
str.append("\n");
for (T t : this) {
str.append(t!=null ? t.toString() : "NULL");
str.append(", ");
i++;
if (i % gridSize == 0) {
str.append("\n");
}
}
return str.toString();
}
}
@@ -19,7 +19,6 @@
package com.seibel.lod.core.util.gridList; package com.seibel.lod.core.util.gridList;
import com.seibel.lod.core.objects.DHRegionPos;
import com.seibel.lod.core.objects.Pos2D; import com.seibel.lod.core.objects.Pos2D;
import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.LodUtil;
@@ -32,9 +32,11 @@ import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
public interface IVersionConstants extends IBindable public interface IVersionConstants extends IBindable
{ {
/** @return the minimum height blocks can be generated */ /** @return the minimum height blocks can be generated */
@Deprecated // This changes per world!
int getMinimumWorldHeight(); int getMinimumWorldHeight();
/** @return the number of generations call per thread. */ /** @return the number of generations call per thread. */
@Deprecated // No longer used
default int getWorldGenerationCountPerThread() { default int getWorldGenerationCountPerThread() {
return 8; return 8;
} }
@@ -1,59 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.wrapperInterfaces.block;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.enums.config.EBlocksToAvoid;
import com.seibel.lod.core.objects.DHBlockPos;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
public abstract class IBlockDetailWrapper
{
// Note: ALL value should be lazily-calculated
// Note: This should be lazily-calculated if block needs tinting to be resolved
public abstract int getAndResolveFaceColor(ELodDirection dir, IChunkWrapper chunk, DHBlockPos blockPos);
public abstract boolean hasFaceCullingFor(ELodDirection dir);
public abstract boolean hasNoCollision();
public abstract boolean noFaceIsFullFace();
public abstract String serialize();
protected abstract boolean isSame(IBlockDetailWrapper iBlockDetail);
@Override
public boolean equals(Object o) {
if (!(o instanceof IBlockDetailWrapper)) return false;
return isSame((IBlockDetailWrapper)o);
}
@Override
public String toString() {
return serialize();
}
public boolean shouldRender(EBlocksToAvoid mode)
{
return !((mode.noCollision && hasNoCollision()) || (mode.nonFull && noFaceIsFullFace()));
}
}
@@ -1,5 +1,15 @@
package com.seibel.lod.core.wrapperInterfaces.block; package com.seibel.lod.core.wrapperInterfaces.block;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.enums.config.EBlocksToAvoid;
import com.seibel.lod.core.objects.DHBlockPos;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
public interface IBlockStateWrapper { public interface IBlockStateWrapper {
String serialize(); String serialize();
// TODO:
// boolean hasFaceCullingFor(ELodDirection dir);
// boolean hasNoCollision();
// boolean noFaceIsFullFace();
} }
@@ -19,11 +19,9 @@
package com.seibel.lod.core.wrapperInterfaces.chunk; package com.seibel.lod.core.wrapperInterfaces.chunk;
import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.handlers.dependencyInjection.IBindable; import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.objects.DHChunkPos;
import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
@@ -38,8 +36,10 @@ public interface IChunkWrapper extends IBindable
} }
int getMinBuildHeight(); int getMinBuildHeight();
int getMaxBuildHeight(); int getMaxBuildHeight();
// FIXME: getHeightMapValue & getMaxY is the same! Which one to keep?
int getHeightMapValue(int xRel, int zRel); int getHeightMapValue(int xRel, int zRel);
int getMaxY(int x, int z);
@Deprecated @Deprecated
int getChunkPosX(); int getChunkPosX();
@@ -49,7 +49,6 @@ public interface IChunkWrapper extends IBindable
int getRegionPosX(); int getRegionPosX();
@Deprecated @Deprecated
int getRegionPosZ(); int getRegionPosZ();
int getMaxY(int x, int z);
int getMaxX(); int getMaxX();
int getMaxZ(); int getMaxZ();
int getMinX(); int getMinX();
@@ -79,16 +79,6 @@ public interface ILodConfigWrapperSingleton extends IBindable
EHorizontalQuality getHorizontalQuality(); EHorizontalQuality getHorizontalQuality();
void setHorizontalQuality(EHorizontalQuality newHorizontalQuality); void setHorizontalQuality(EHorizontalQuality newHorizontalQuality);
EDropoffQuality getDropoffQuality();
void setDropoffQuality(EDropoffQuality newDropoffQuality);
default EDropoffQuality getResolvedDropoffQuality() {
EDropoffQuality dropoffQuality = Config.Client.Graphics.Quality.dropoffQuality.get();
if (dropoffQuality == EDropoffQuality.AUTO)
dropoffQuality = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() < 128 ?
EDropoffQuality.SMOOTH_DROPOFF : EDropoffQuality.PERFORMANCE_FOCUSED;
return dropoffQuality;
}
public void setTransparency(ETransparency newTransparency); public void setTransparency(ETransparency newTransparency);
public ETransparency getTransparency(); public ETransparency getTransparency();
@@ -179,15 +179,6 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton
Config.Client.Graphics.Quality.horizontalQuality.set(newHorizontalQuality); Config.Client.Graphics.Quality.horizontalQuality.set(newHorizontalQuality);
} }
@Override
public EDropoffQuality getDropoffQuality() {
return Config.Client.Graphics.Quality.dropoffQuality.get();
}
@Override
public void setDropoffQuality(EDropoffQuality newDropoffQuality) {
Config.Client.Graphics.Quality.dropoffQuality.set(newDropoffQuality);
}
@Override @Override
public void setTransparency(ETransparency newTransparency) { public void setTransparency(ETransparency newTransparency) {
Config.Client.Graphics.Quality.transparency.set(newTransparency); Config.Client.Graphics.Quality.transparency.set(newTransparency);
@@ -130,7 +130,7 @@ public interface IMinecraftClientWrapper extends IBindable
* Error: <strong>ExceptionClass: exceptionErrorMessage</strong> <br> * Error: <strong>ExceptionClass: exceptionErrorMessage</strong> <br>
* Exit Code: -1 <br> * Exit Code: -1 <br>
*/ */
void crashMinecraft(String errorMessage, Throwable exception); void crashMinecraft(String errorMessage, Throwable exception); //FIXME: Move to IMinecraftSharedWrapper
Object getOptionsObject(); Object getOptionsObject();
@@ -1,39 +0,0 @@
/*
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2022 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.wrapperInterfaces.world;
import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
import com.seibel.lod.core.objects.DHBlockPos;
/**
* Contains everything related to biome colors.
*
* @author James Seibel
* @version 3-5-2022
*/
public interface IBiomeColorWrapperSingleton extends IBindable
{
IBiomeColorWrapperSingleton getInstance();
int getGrassColor(ILevelWrapper world, DHBlockPos blockPos);
int getWaterColor(ILevelWrapper world, DHBlockPos blockPos);
int getFoliageColor(ILevelWrapper world, DHBlockPos blockPos);
}