Merge remote-tracking branch 'origin/main' into main

# Conflicts:
#	src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java
This commit is contained in:
Ran
2022-02-21 17:29:40 +06:00
11 changed files with 84 additions and 229 deletions
@@ -184,7 +184,8 @@ public class ClientApi
toBeLoaded.remove(pos);
continue;
}
//if (!chunk.isLightCorrect()) continue;
if (!chunk.isLightCorrect()) continue;
if (!chunk.doesNearbyChunksExist()) continue;
toBeLoaded.remove(pos);
generating.add(pos);
//ApiShared.LOGGER.info("Lod Generation trying "+pos+". Remining: " +toBeLoaded.size());
@@ -321,7 +321,7 @@ public class LodBufferBuilderFactory {
CompletableFuture<Void> allFutures = CompletableFuture
.allOf(futuresBuffer.toArray(new CompletableFuture[futuresBuffer.size()]));
try {
allFutures.get(60, TimeUnit.SECONDS);
allFutures.get(5, TimeUnit.MINUTES);
} catch (TimeoutException te) {
ApiShared.LOGGER.error("LodBufferBuilder timed out: ", te);
bufferBuilderThreadFactory.dumpAllThreadStacks();
@@ -22,27 +22,23 @@ package com.seibel.lod.core.builders.lodBuilding;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.LodDirection;
import com.seibel.lod.core.enums.config.BlocksToAvoid;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.objects.lod.LodDimension;
import com.seibel.lod.core.objects.lod.LodRegion;
import com.seibel.lod.core.objects.lod.LodWorld;
import com.seibel.lod.core.util.ColorUtil;
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.LodThreadFactory;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorSingletonWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.BlockDetail;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
@@ -58,7 +54,6 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper;
public class LodBuilder
{
private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class);
private static final IBlockColorSingletonWrapper BLOCK_COLOR = SingletonHandler.get(IBlockColorSingletonWrapper.class);
/** This cannot be final! Different world have different height, and in menu, this causes Null Exceptions*/
@@ -137,7 +132,7 @@ public class LodBuilder
}
catch (RuntimeException e)
{
e.printStackTrace();
ClientApi.LOGGER.error("LodBuilder Thread Uncaught Exception: ", e);
// // if the world changes while LODs are being generated
// // they will throw errors as they try to access things that no longer
// // exist.
@@ -167,6 +162,7 @@ public class LodBuilder
if (MC.getWrappedClientWorld() == null)
return false;
if (!chunk.isLightCorrect()) return false;
if (!chunk.doesNearbyChunksExist()) return false;
// generate the LODs
@@ -180,7 +176,7 @@ public class LodBuilder
int subZ = i%16;
writeVerticalData(data, i*maxVerticalData, maxVerticalData, chunk, config, subX, subZ);
//if (DataPointUtil.isVoid(data[i*maxVerticalData]))
// ApiShared.LOGGER.debug("Datapoint is Void: {}, {}", chunk.getMinX()+subX, chunk.getMinZ()+subZ);
// ClientApi.LOGGER.debug("Datapoint is Void: {}, {}", chunk.getMinX()+subX, chunk.getMinZ()+subZ);
if (!DataPointUtil.doesItExist(data[i*maxVerticalData]))
throw new RuntimeException("writeVerticalData result: Datapoint does not exist at "+ chunk.getMinX()+subX +", "+ chunk.getMinZ()+subZ);
if (DataPointUtil.getGenerationMode(data[i*maxVerticalData]) != config.distanceGenerationMode.complexity)
@@ -193,6 +189,7 @@ public class LodBuilder
}
}
if (!chunk.isLightCorrect()) return false;
if (!chunk.doesNearbyChunksExist()) return false;
if (genAll) {
return writeAllLodNodeData(lodDim, region, chunk.getChunkPosX(), chunk.getChunkPosZ(), data, config, override);
@@ -200,7 +197,7 @@ public class LodBuilder
return writePartialLodNodeData(lodDim, region, chunk.getChunkPosX(), chunk.getChunkPosZ(), data, config, override);
}
} catch (RuntimeException e) {
ApiShared.LOGGER.error("LodBuilder encountered an error on building lod for chunk {}: {}", chunk ,e);
ClientApi.LOGGER.error("LodBuilder encountered an error on building lod: ", e);
return false;
}
@@ -213,7 +210,7 @@ public class LodBuilder
try {
if (region.getMinDetailLevel()!= 0) {
if (!LodUtil.checkRamUsage(0.05, 16)) {
ApiShared.LOGGER.debug("LodBuilder: Not enough RAM avalible for loading files to build lods! Returning...");
ClientApi.LOGGER.debug("LodBuilder: Not enough RAM avalible for loading files to build lods! Returning...");
return false;
}
@@ -221,7 +218,7 @@ public class LodBuilder
if (region!=newRegion)
throw new RuntimeException();
}
//ApiShared.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}",
//ClientApi.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}",
// chunk.getChunkPosX(), chunk.getChunkPosZ(), chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode);
region.addChunkOfData((byte)0, chunkX*16, chunkZ*16, 16, 16, data, data.length/16/16, override);
region.regenerateLodFromArea((byte)0, chunkX*16, chunkZ*16, 16, 16);
@@ -269,7 +266,7 @@ public class LodBuilder
for (int i=0; i<data.length; i+=vertQual) {
if (!DataPointUtil.doesItExist(data[i]) ||
DataPointUtil.getGenerationMode(data[i]) != config.distanceGenerationMode.complexity) {
ApiShared.LOGGER.error("NULL data at {}, detail {}, vertQual {}, lodCount {}, chunkPos [{},{}]\n"
ClientApi.LOGGER.error("NULL data at {}, detail {}, vertQual {}, lodCount {}, chunkPos [{},{}]\n"
+ "Data: {}",
i, targetLevel, vertQual, lodCount, chunkX, chunkZ, DataPointUtil.toString(data[i]));
throw new RuntimeException("Null data!");
@@ -277,7 +274,7 @@ public class LodBuilder
}
//ApiShared.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}",
//ClientApi.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}",
// chunk.getChunkPosX(), chunk.getChunkPosZ(), chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode);
region.addChunkOfData(targetLevel,
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, targetLevel),
@@ -295,7 +292,7 @@ public class LodBuilder
config.distanceGenerationMode))
throw new RuntimeException("data at detail "+ targetLevel+" is still null after writes to it!");
} catch (Exception e) {
e.printStackTrace();
ClientApi.LOGGER.error("LodBuilder encountered an error on writePartialLodNodeData: ", e);
} finally {
region.isWriting.decrementAndGet();
}
@@ -367,8 +364,8 @@ public class LodBuilder
int cy = y+dir.getNormal().y;
int cz = z+dir.getNormal().z;
if (!chunk.blockPosInsideChunk(cx, cy, cz)) return true;
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(cx, cy, cz);
if (block == null || block.hasNoCollision() || block.isToAvoid() || block.isNonFull() || block.hasNoCollision())
BlockDetail block = chunk.getBlockDetail(cx, cy, cz);
if (block == null || !block.isFullBlock)
return true;
}
return false;
@@ -378,27 +375,24 @@ public class LodBuilder
* Find the lowest valid point from the bottom.
* Used when creating a vertical LOD.
*/
private int determineBottomPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs, boolean strictEdge)
private int determineBottomPointFrom(IChunkWrapper chunk, LodBuilderConfig builderConfig, int xAbs, int yAbs, int zAbs, boolean strictEdge)
{
int depth = chunk.getMinBuildHeight();
int colorOfBlock = 0;
if (strictEdge)
{
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(xAbs, yAbs + 1, zAbs);
if (block != null && !block.isToAvoid()
&& ((this.config.client().worldGenerator().getBlocksToAvoid().nonFull && block.isNonFull())
|| (this.config.client().worldGenerator().getBlocksToAvoid().noCollision && block.hasNoCollision())))
{
colorOfBlock = chunk.getBlockColorWrapper(xAbs, yAbs + 1, zAbs).getColor();
BlockDetail blockAbove = chunk.getBlockDetail(xAbs, yAbs + 1, zAbs);
if (blockAbove != null && !blockAbove.shouldRender(config.client().worldGenerator().getBlocksToAvoid()))
{ // The above block is skipped. Lets use its skipped color for currrent block
colorOfBlock = blockAbove.color;
}
if (colorOfBlock == 0)
colorOfBlock = chunk.getBlockColorWrapper(xAbs, yAbs, zAbs).getColor();
if (colorOfBlock == 0) colorOfBlock = chunk.getBlockDetail(xAbs, yAbs, zAbs).color;
}
for (int y = yAbs - 1; y >= chunk.getMinBuildHeight(); y--)
{
if (!isLayerValidLodPoint(chunk, xAbs, y, zAbs)
|| (strictEdge && hasCliffFace(chunk, xAbs, y, zAbs) && colorOfBlock != chunk.getBlockColorWrapper(xAbs, y, zAbs).getColor()))
|| (strictEdge && hasCliffFace(chunk, xAbs, y, zAbs) && colorOfBlock != chunk.getBlockDetail(xAbs, y, zAbs).color))
{
depth = (short) (y + 1);
break;
@@ -444,16 +438,20 @@ public class LodBuilder
}
else
{
colorInt = getColorForBlock(chunk, x, y, z);
BlockDetail detail = chunk.getBlockDetail(x, y, z);
colorInt = detail == null ? 0 : detail.color;
// if we are skipping non-full and non-solid blocks that means we ignore
// snow, flowers, etc. Get the above block so we can still get the color
// of the snow, flower, etc. that may be above this block
int aboveColorInt = 0;
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(x, y + 1, z);
if (block != null && ((config.client().worldGenerator().getBlocksToAvoid().nonFull && block.isNonFull())
|| (config.client().worldGenerator().getBlocksToAvoid().noCollision && block.hasNoCollision())))
aboveColorInt = getColorForBlock(chunk, x, y + 1, z);
if (chunk.blockPosInsideChunk(x, y+1, z)) {
BlockDetail blockAbove = chunk.getBlockDetail(x, y+1, z);
if (blockAbove != null && !blockAbove.shouldRender(config.client().worldGenerator().getBlocksToAvoid()))
{ // The above block is skipped. Lets use its skipped color for currrent block
aboveColorInt = blockAbove.color;
}
}
//if (colorInt == 0 && yAbs > 0)
// if this block is invisible, check the block below it
@@ -545,65 +543,11 @@ public class LodBuilder
return blockLight + (skyLight << 4);
}
/** Returns a color int for the given block. */
private int getColorForBlock(IChunkWrapper chunk, int x, int y, int z)
{
int colorOfBlock;
int colorInt;
IBlockShapeWrapper blockShapeWrapper = chunk.getBlockShapeWrapper(x, y, z);
if (blockShapeWrapper == null || blockShapeWrapper.isToAvoid())
return 0;
IBlockColorWrapper blockColorWrapper;
if (chunk.isWaterLogged(x, y, z))
blockColorWrapper = BLOCK_COLOR.getWaterColor();
else
blockColorWrapper = chunk.getBlockColorWrapper(x, y, z);
colorOfBlock = blockColorWrapper.getColor();
if (blockColorWrapper.hasTint())
{
IBiomeWrapper biome = chunk.getBiome(x, y, z);
int tintValue;
if (blockColorWrapper.hasGrassTint())
// grass and green plants
tintValue = biome.getGrassTint(0,0);
else if (blockColorWrapper.hasFolliageTint())
tintValue = biome.getFolliageTint();
else
//we can reintroduce this with the wrappers
tintValue = biome.getWaterTint();
colorInt = ColorUtil.multiplyRGBcolors(tintValue | 0xFF000000, colorOfBlock);
}
else
colorInt = colorOfBlock;
return colorInt;
}
/** Is the block at the given blockPos a valid LOD point? */
private boolean isLayerValidLodPoint(IChunkWrapper chunk, int x, int y, int z)
{
if (chunk.isWaterLogged(x, y, z))
return true;
boolean nonFullAvoidance = config.client().worldGenerator().getBlocksToAvoid().nonFull;
boolean noCollisionAvoidance = config.client().worldGenerator().getBlocksToAvoid().noCollision;
IBlockShapeWrapper block = chunk.getBlockShapeWrapper(x, y, z);
return block != null
&& !block.isToAvoid()
&& !(nonFullAvoidance && block.isNonFull())
&& !(noCollisionAvoidance && block.hasNoCollision());
BlocksToAvoid avoid = config.client().worldGenerator().getBlocksToAvoid();
BlockDetail block = chunk.getBlockDetail(x, y, z);
return block != null && block.shouldRender(avoid);
}
}
@@ -1,6 +1,7 @@
package com.seibel.lod.core.objects;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
/*
import com.seibel.lod.core.wrapperInterfaces.block.BlockDetail;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import java.util.Objects;
@@ -9,15 +10,15 @@ import java.util.concurrent.ConcurrentMap;
public class BlockBiomeCouple
{
public static final ConcurrentMap<IBlockColorWrapper, BlockBiomeCouple> noBiomeIstanceCache = new ConcurrentHashMap<>();
public static ConcurrentMap<IBiomeWrapper, ConcurrentMap<IBlockColorWrapper, BlockBiomeCouple>> withBiomeIstanceCache = new ConcurrentHashMap<>();
public static final ConcurrentMap<BlockDetail, BlockBiomeCouple> noBiomeIstanceCache = new ConcurrentHashMap<>();
public static ConcurrentMap<IBiomeWrapper, ConcurrentMap<BlockDetail, BlockBiomeCouple>> withBiomeIstanceCache = new ConcurrentHashMap<>();
String blockName;
String biomeName;
String coupleName;
IBiomeWrapper biomeColor;
IBlockColorWrapper blockColor;
BlockDetail blockColor;
public static void addBlockBiomeToCache(IBlockColorWrapper blockColor){
}
@@ -101,3 +102,4 @@ public class BlockBiomeCouple
}
*/
@@ -17,7 +17,7 @@ public class LodQuadBuilder {
static final int MAX_BUFFER_SIZE = (1024 * 1024 * 1);
static final int QUAD_BYTE_SIZE = (12 * 6);
static final int MAX_QUADS_PER_BUFFER = MAX_BUFFER_SIZE / QUAD_BYTE_SIZE;
static final int MAX_MERGED_QUAD_SIZE = 64;
//static final int MAX_MERGED_QUAD_SIZE = 64;
static class Quad {
final short x;
@@ -88,7 +88,7 @@ public class LodQuadBuilder {
{
if (dir != o.dir)
return false;
if (w0 >= MAX_MERGED_QUAD_SIZE) return false;
//if (w0 >= MAX_MERGED_QUAD_SIZE) return false;
switch (dir.getAxis())
{
case X:
@@ -157,7 +157,7 @@ public class LodQuadBuilder {
{
if (dir != o.dir)
return false;
if (w1 >= MAX_MERGED_QUAD_SIZE) return false;
//if (w1 >= MAX_MERGED_QUAD_SIZE) return false;
switch (dir.getAxis())
{
case X:
@@ -33,7 +33,6 @@ public class ColorUtil
{
private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class);
public static int rgbToInt(int red, int green, int blue)
{
return (0xFF << 24) | (red << 16) | (green << 8) | blue;
@@ -0,0 +1,28 @@
package com.seibel.lod.core.wrapperInterfaces.block;
import com.seibel.lod.core.enums.config.BlocksToAvoid;
import com.seibel.lod.core.util.ColorUtil;
public class BlockDetail
{
public final int color;
public final boolean isFullBlock;
public final boolean hasNoCollision;
public final boolean hasOnlyNonFullFace;
public BlockDetail(int c, boolean full, boolean noCol, boolean nonFullFace) {
color = c;
isFullBlock = full;
hasNoCollision = noCol;
hasOnlyNonFullFace = nonFullFace;
}
public boolean shouldRender(BlocksToAvoid mode) {
return !((mode.noCollision && hasNoCollision) || (mode.nonFull && hasOnlyNonFullFace));
}
public String toString() {
return "[color: "+ColorUtil.toString(color)+", isFullBlock: "+isFullBlock
+", hasNoCollision: "+hasNoCollision+", hasOnlyNonFullFace: "+hasOnlyNonFullFace+"]";
}
}
@@ -1,35 +0,0 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.wrapperInterfaces.block;
/**
* Contains methods that would have been static in BlockColorWrapper.
* Since interfaces can't create/implement static methods we have
* to split the object up in two.
*
* @author James Seibel
* @version 11-17-2021
*/
public interface IBlockColorSingletonWrapper
{
/** @returns the base color of water (grey) */
IBlockColorWrapper getWaterColor();
}
@@ -1,52 +0,0 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.wrapperInterfaces.block;
/**
* @author James Seibel
* @version 11-17-2021
*/
public interface IBlockColorWrapper
{
//--------------//
//Colors getters//
//--------------//
boolean hasColor();
String getName();
int getColor();
//------------//
//Tint getters//
//------------//
boolean hasTint();
boolean hasGrassTint();
boolean hasFolliageTint();
boolean hasWaterTint();
}
@@ -1,39 +0,0 @@
/*
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.lod.core.wrapperInterfaces.block;
/**
* @author James Seibel
* @version 11-20-2021
*/
public interface IBlockShapeWrapper
{
boolean ofBlockToAvoid();
//-----------------//
//Avoidance getters//
//-----------------//
boolean isNonFull();
boolean hasNoCollision();
boolean isToAvoid();
}
@@ -19,10 +19,15 @@
package com.seibel.lod.core.wrapperInterfaces.chunk;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper;
import org.jetbrains.annotations.Nullable;
import com.seibel.lod.core.wrapperInterfaces.block.BlockDetail;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
/**
* @author James Seibel
* @version 11-17-2021
@@ -38,8 +43,8 @@ public interface IChunkWrapper
int getHeightMapValue(int xRel, int zRel);
IBiomeWrapper getBiome(int x, int y, int z);
IBlockColorWrapper getBlockColorWrapper(int x, int y, int z);
IBlockShapeWrapper getBlockShapeWrapper(int x, int y, int z);
BlockDetail getBlockDetail(int x, int y, int z);
int getChunkPosX();
int getChunkPosZ();
@@ -68,4 +73,6 @@ public interface IChunkWrapper
&& y>=getMinBuildHeight() && y<getMaxBuildHeight()
&& z>=getMinZ() && z<=getMaxZ());
}
boolean doesNearbyChunksExist();
}