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

# Conflicts:
#	src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java
#	src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java
This commit is contained in:
Leonardo
2021-10-14 02:28:24 +02:00
55 changed files with 598 additions and 833 deletions
+24 -25
View File
@@ -15,11 +15,11 @@
* 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;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.proxy.ClientProxy;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
@@ -35,7 +35,6 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
* <br>
* If you are looking for the real start of the mod
* check out the ClientProxy.
*
* @author James Seibel
* @version 7-3-2021
*/
@@ -53,28 +52,28 @@ public class LodMain
}
public LodMain()
{
// Register the methods
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientStart);
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
}
private void onClientStart(final FMLClientSetupEvent event)
{
client_proxy = new ClientProxy();
public LodMain()
{
// Register the methods
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::init);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientStart);
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
}
private void onClientStart(final FMLClientSetupEvent event)
{
client_proxy = new ClientProxy();
MinecraftForge.EVENT_BUS.register(client_proxy);
}
@SubscribeEvent
public void onServerStarting(FMLServerStartingEvent event)
{
// this is called when the server starts
}
}
@SubscribeEvent
public void onServerStarting(FMLServerStartingEvent event)
{
// this is called when the server starts
}
}
+2 -2
View File
@@ -15,16 +15,16 @@
* 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;
/**
* This file is similar to mcmod.info
*
* @author James Seibel
* @version 08-29-2021
*/
public final class ModInfo
{
{
public static final String MODID = "lod";
public static final String MODNAME = "LOD";
public static final String MODAPI = "LodAPI";
@@ -15,24 +15,9 @@
* 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.builders.bufferBuilding;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.GL45;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.lod.builders.bufferBuilding.lodTemplates.Box;
@@ -45,22 +30,30 @@ import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.proxy.GlProxy;
import com.seibel.lod.render.LodRenderer;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.ThreadMapUtil;
import com.seibel.lod.util.*;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.GL45;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
/**
* This object is used to create NearFarBuffer objects.
*
* @author James Seibel
* @version 10-10-2021
*/
@@ -72,7 +65,7 @@ public class LodBufferBuilder
public static final ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfBufferBuilderThreads.get(), new ThreadFactoryBuilder().setNameFormat("Buffer-Builder-%d").build());
/**
* When uploading to a buffer that is too small,
* When uploading to a buffer that is too small,
* recreate it this many times bigger than the upload payload
*/
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.5;
@@ -95,7 +88,7 @@ public class LodBufferBuilder
* How many buffers there are for the given region. <Br>
* This is done because some regions may require more memory than
* can be directly allocated, so we split the regions into smaller sections. <Br>
* This keeps track of those sections.
* This keeps track of those sections.
*/
public volatile int[][] numberOfBuffersPerRegion;
@@ -109,7 +102,7 @@ public class LodBufferBuilder
/** used to debug how the buildableStorageBuffers are growing */
public int[][][] bufferPreviousCapacity;
/**
/**
* This is toggled when the buffers are swapped, so we only
* display the expansion log for one set of buffers
*/
@@ -187,9 +180,7 @@ public class LodBufferBuilder
Thread thread = new Thread(() ->
{
generateLodBuffersThread(renderer, lodDim, playerBlockPos, fullRegen);
});
generateLodBuffersThread(renderer, lodDim, playerBlockPos, fullRegen));
mainGenThread.execute(thread);
}
@@ -344,9 +335,9 @@ public class LodBufferBuilder
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z;
if (posToRender.contains(detailLevel, xAdj, zAdj)
&& (gameChunkRenderDistance < Math.abs(chunkXdist)
|| gameChunkRenderDistance < Math.abs(chunkZdist)
|| !(vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& (!LodUtil.isBorderChunk(vanillaRenderedChunks, chunkXdist + gameChunkRenderDistance + 1, chunkZdist + gameChunkRenderDistance + 1) || smallRenderDistance))))
|| gameChunkRenderDistance < Math.abs(chunkZdist)
|| !(vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& (!LodUtil.isBorderChunk(vanillaRenderedChunks, chunkXdist + gameChunkRenderDistance + 1, chunkZdist + gameChunkRenderDistance + 1) || smallRenderDistance))))
{
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++)
{
@@ -379,7 +370,7 @@ public class LodBufferBuilder
} // for pos to in list to render
// the thread executed successfully
// the thread executed successfully
return true;
};
@@ -412,7 +403,7 @@ public class LodBufferBuilder
long buildTime = endTime - startTime;
@SuppressWarnings("unused")
long executeTime = executeEnd - executeStart;
// ClientProxy.LOGGER.info("Thread Build time: " + buildTime + " ms" + '\n' +
// "thread execute time: " + executeTime + " ms");
@@ -542,7 +533,7 @@ public class LodBufferBuilder
// create the buffer storage (GPU memory)
buildableStorageBufferIds[x][z][i] = GL45.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buildableStorageBufferIds[x][z][i]);
GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0); // the 0 flag means to create the storage in the GPU's memory
GL45.glBufferStorage(GL15.GL_ARRAY_BUFFER, regionMemoryRequired, 0); // the 0 flag means to create the storage in the GPUs memory
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
drawableStorageBufferIds[x][z][i] = GL45.glGenBuffers();
@@ -584,9 +575,9 @@ public class LodBufferBuilder
// This way we don't have to worry about what context this
// was called from (if any).
RenderSystem.recordRenderCall(() -> {
GL45.glDeleteBuffers(buildableId);
GL45.glDeleteBuffers(drawableId);
});
GL45.glDeleteBuffers(buildableId);
GL45.glDeleteBuffers(drawableId);
});
}
}
}
@@ -607,7 +598,7 @@ public class LodBufferBuilder
{
for (int k = 0; k < buildableVbos[i][j].length; k++)
{
int buildableId;
int buildableId;
int drawableId;
// variables passed into a lambda expression
@@ -622,14 +613,14 @@ public class LodBufferBuilder
drawableId = drawableVbos[i][j][k].id;
else
drawableId = 0;
RenderSystem.recordRenderCall(() -> {
if (buildableId != 0)
GL45.glDeleteBuffers(buildableId);
if (drawableId != 0)
GL45.glDeleteBuffers(drawableId);
});
});
}
}
}
@@ -701,7 +692,7 @@ public class LodBufferBuilder
for (int i = 0; i < buildableBuffers[x][z].length; i++)
{
ByteBuffer uploadBuffer = buildableBuffers[x][z][i].popNextBuffer().getSecond();
vboUpload(buildableVbos[x][z][i], buildableStorageBufferIds[x][z][i], uploadBuffer, x,z,i, true);
vboUpload(buildableVbos[x][z][i], buildableStorageBufferIds[x][z][i], uploadBuffer, x, z, i, true);
lodDim.setRegenRegionBufferByArrayIndex(x, z, false);
}
}
@@ -727,9 +718,9 @@ public class LodBufferBuilder
/** Uploads the uploadBuffer into the VBO and then into GPU memory. */
private void vboUpload(VertexBuffer vbo, int storageBufferId, ByteBuffer uploadBuffer,
int xVboIndex, int zVboIndex, int iVboIndex, boolean allowBufferExpansion)
// x/zVboIndex are just used for the debugging console logging
// and should be removed when the logger is removed.
int xVboIndex, int zVboIndex, int iVboIndex, boolean allowBufferExpansion)
// x/zVboIndex are just used for the debugging console logging
// and should be removed when the logger is removed.
{
// this shouldn't happen, but just to be safe
if (vbo.id != -1 && GlProxy.getInstance().getGlContext() == GlProxyContext.LOD_BUILDER)
@@ -776,19 +767,19 @@ public class LodBufferBuilder
if (printExpansionLog)
/*if (printExpansionLog)
{
// NOTE: this will display twice because we are double buffering
// (using 1 buffer to generate into and one to draw)
// ClientProxy.LOGGER.info("vbo (" + xVboIndex + "," + zVboIndex + ") expanded: " + bufferPreviousCapacity[xVboIndex][zVboIndex][iVboIndex] + " -> " + (int)(uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER));
// bufferPreviousCapacity[xVboIndex][zVboIndex][iVboIndex] = (int) (uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER);
}
ClientProxy.LOGGER.info("vbo (" + xVboIndex + "," + zVboIndex + ") expanded: " + bufferPreviousCapacity[xVboIndex][zVboIndex][iVboIndex] + " -> " + (int)(uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER));
bufferPreviousCapacity[xVboIndex][zVboIndex][iVboIndex] = (int) (uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER);
}*/
}
}
else
{
// upload the buffer into system memory...
vboBuffer.put(uploadBuffer);
vboBuffer.put(uploadBuffer);
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
// ...then upload into GPU memory
@@ -797,7 +788,7 @@ public class LodBufferBuilder
GL45.glCopyNamedBufferSubData(vbo.id, storageBufferId, 0, 0, uploadBuffer.capacity());
}
}
catch(Exception e)
catch (Exception e)
{
ClientProxy.LOGGER.error("vboUpload failed: " + e.getClass().getSimpleName());
e.printStackTrace();
@@ -18,20 +18,18 @@
package com.seibel.lod.builders.bufferBuilding.lodTemplates;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.util.ColorUtil;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import java.util.Map;
/**
* This is the abstract class used to create different
* BufferBuilders.
*
* @author James Seibel
* @version 10-10-2021
*/
@@ -16,7 +16,6 @@ import java.util.Map;
/**
* Similar to Minecraft's AxisAlignedBoundingBox.
*
* @author Leonardo Amato
* @version 10-2-2021
*/
@@ -147,7 +146,9 @@ public class Box
public final int[] colorMap;
/** The original color (before shading) of this box */
public int color;
/** */
/**
*
*/
public final Map<Direction, int[]> adjHeight;
public final Map<Direction, int[]> adjDepth;
@@ -241,6 +242,7 @@ public class Box
/** determine which faces should be culled */
public void setUpCulling(int cullingDistance, BlockPos playerPos)
{
//TODO is passing playerPos needed?
playerPos = MinecraftWrapper.INSTANCE.getPlayer().blockPosition();
for (Direction direction : DIRECTIONS)
{
@@ -398,12 +400,7 @@ public class Box
}
}
/**
* We use this method to set the various width of the column
* @param xWidth
* @param yWidth
* @param zWidth
*/
/** We use this method to set the various width of the column */
public void setWidth(int xWidth, int yWidth, int zWidth)
{
boxWidth[X] = xWidth;
@@ -411,12 +408,7 @@ public class Box
boxWidth[Z] = zWidth;
}
/**
* We use this method to set the various offset of the column
* @param xOffset
* @param yOffset
* @param zOffset
*/
/** We use this method to set the various offset of the column */
public void setOffset(int xOffset, int yOffset, int zOffset)
{
boxOffset[X] = xOffset;
@@ -449,7 +441,6 @@ public class Box
/**
*
* @param direction direction of the face we want to render
* @param vertexIndex index of the vertex of the face (0-1-2-3)
* @return position x of the relative vertex
@@ -460,7 +451,6 @@ public class Box
}
/**
*
* @param direction direction of the face we want to render
* @param vertexIndex index of the vertex of the face (0-1-2-3)
* @return position y of the relative vertex
@@ -471,7 +461,6 @@ public class Box
}
/**
*
* @param direction direction of the face we want to render
* @param vertexIndex index of the vertex of the face (0-1-2-3)
* @param adjIndex, index of the n-th culled face of this direction
@@ -499,7 +488,6 @@ public class Box
}
/**
*
* @param direction direction of the face we want to render
* @param vertexIndex index of the vertex of the face (0-1-2-3)
* @return position z of the relative vertex
@@ -18,20 +18,18 @@
package com.seibel.lod.builders.bufferBuilding.lodTemplates;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.LodUtil;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import java.util.Map;
/**
* Builds LODs as rectangular prisms.
*
* @author James Seibel
* @version 10-10-2021
*/
@@ -87,11 +85,9 @@ public class CubicLodTemplate extends AbstractLodTemplate
return;
if (depth == height)
{
// if the top and bottom points are at the same height
// render this LOD as 1 block thick
height++;
}
// offset the AABB by its x/z position in the world since
// it uses doubles to specify its location, unlike the model view matrix
@@ -18,22 +18,20 @@
package com.seibel.lod.builders.bufferBuilding.lodTemplates;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.proxy.ClientProxy;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import java.util.Map;
/**
* TODO DynamicLodTemplate
* Chunks smoothly transition between
* each other, unless a neighboring chunk
* is at a significantly different height.
*
* @author James Seibel
* @version 06-16-2021
*/
@@ -18,20 +18,18 @@
package com.seibel.lod.builders.bufferBuilding.lodTemplates;
import java.util.Map;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.proxy.ClientProxy;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import java.util.Map;
/**
* TODO #21 TriangularLodTemplate
* Builds each LOD chunk as a singular rectangular prism.
*
* @author James Seibel
* @version 06-16-2021
*/
@@ -18,14 +18,6 @@
package com.seibel.lod.builders.lodBuilding;
import java.awt.Color;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.HorizontalResolution;
@@ -33,26 +25,9 @@ import com.seibel.lod.enums.VerticalQuality;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodRegion;
import com.seibel.lod.objects.LodWorld;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.ThreadMapUtil;
import com.seibel.lod.util.*;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.block.AbstractPlantBlock;
import net.minecraft.block.AbstractTopPlantBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.BushBlock;
import net.minecraft.block.FlowerBlock;
import net.minecraft.block.GrassBlock;
import net.minecraft.block.IGrowable;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.TallGrassBlock;
import net.minecraft.block.*;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@@ -69,13 +44,19 @@ import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.gen.Heightmap;
import net.minecraftforge.client.model.data.ModelDataMap;
import java.awt.*;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* This object is in charge of creating Lod related objects. (specifically: Lod
* World, Dimension, and Region objects)
*
* @author Leonardo Amato
* @author James Seibel
* @version 10-9-2021
@@ -89,7 +70,6 @@ public class LodBuilder
public static final Direction[] directions = new Direction[] { Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN };
public static final int CHUNK_DATA_WIDTH = LodUtil.CHUNK_WIDTH;
public static final int CHUNK_SECTION_HEIGHT = CHUNK_DATA_WIDTH;
public static final Heightmap.Type DEFAULT_HEIGHTMAP = Heightmap.Type.WORLD_SURFACE_WG;
public static final ConcurrentMap<Block, Integer> colorMap = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, Integer> tintColor = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, Boolean> toTint = new ConcurrentHashMap<>();
@@ -107,7 +87,7 @@ public class LodBuilder
/**
* How wide LodDimensions should be in regions <br>
* Is automatically set before the first frame in ClientProxy.
* Is automatically set before the first frame in ClientProxy.
*/
public int defaultDimensionWidthInRegions = 0;
@@ -126,7 +106,7 @@ public class LodBuilder
public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world, DistanceGenerationMode generationMode)
{
if (lodWorld == null || !lodWorld.getIsWorldLoaded())
if (lodWorld == null || lodWorld.getIsWorldNotLoaded())
return;
// don't try to create an LOD object
@@ -172,7 +152,6 @@ public class LodBuilder
/**
* Creates a LodNode for a chunk in the given world.
*
* @throws IllegalArgumentException thrown if either the chunk or world is null.
*/
public void generateLodNodeFromChunk(LodDimension lodDim, IChunk chunk) throws IllegalArgumentException
@@ -182,7 +161,6 @@ public class LodBuilder
/**
* Creates a LodNode for a chunk in the given world.
*
* @throws IllegalArgumentException thrown if either the chunk or world is null.
*/
public void generateLodNodeFromChunk(LodDimension lodDim, IChunk chunk, LodBuilderConfig config)
@@ -251,9 +229,7 @@ public class LodBuilder
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
}
/**
* creates a vertical DataPoint
*/
/** creates a vertical DataPoint */
private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ)
{
// equivalent to 2^detailLevel
@@ -375,9 +351,7 @@ public class LodBuilder
return depth;
}
/**
* Find the highest valid point from the Top
*/
/** Find the highest valid point from the Top */
private short determineHeightPointFrom(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, int yAbs, BlockPos.Mutable blockPos)
{
short height = DEFAULT_HEIGHT;
@@ -447,9 +421,7 @@ public class LodBuilder
return colorInt;
}
/**
* Gets the light value for the given block position
*/
/** Gets the light value for the given block position */
private int getLightValue(IChunk chunk, BlockPos.Mutable blockPos, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
{
int skyLight;
@@ -518,8 +490,8 @@ public class LodBuilder
for (Direction direction : directions)
{
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(blockState).getQuads(blockState, direction, new Random(0), dataMap);
listSize = Math.max(listSize,quads.size());
for(BakedQuad bakedQuad : quads)
listSize = Math.max(listSize, quads.size());
for (BakedQuad bakedQuad : quads)
{
isTinted |= bakedQuad.isTinted();
tintIndex = Math.max(tintIndex, bakedQuad.getTintIndex());
@@ -614,19 +586,19 @@ public class LodBuilder
private boolean useGrassTint(Block block)
{
return block instanceof GrassBlock
|| block instanceof BushBlock
|| block instanceof IGrowable
|| block instanceof AbstractPlantBlock
|| block instanceof AbstractTopPlantBlock
|| block instanceof TallGrassBlock;
|| block instanceof BushBlock
|| block instanceof IGrowable
|| block instanceof AbstractPlantBlock
|| block instanceof AbstractTopPlantBlock
|| block instanceof TallGrassBlock;
}
/** determine if the given block should use the biome's foliage color */
private boolean useLeafTint(Block block)
{
return block instanceof LeavesBlock
|| block == Blocks.VINE
|| block == Blocks.SUGAR_CANE;
|| block == Blocks.VINE
|| block == Blocks.SUGAR_CANE;
}
/** determine if the given block should use the biome's water color */
@@ -639,7 +611,7 @@ public class LodBuilder
private int getColorForBlock(IChunk chunk, BlockPos blockPos)
{
int blockColor;
int colorInt = 0;
int colorInt;
int xRel = blockPos.getX() - chunk.getPos().getMinBlockX();
int zRel = blockPos.getZ() - chunk.getPos().getMinBlockZ();
@@ -655,8 +627,8 @@ public class LodBuilder
// block special cases
// TODO: this needs to be replaced by a config file of some sort
if (blockState == Blocks.AIR.defaultBlockState()
|| blockState == Blocks.CAVE_AIR.defaultBlockState()
|| blockState == Blocks.BARRIER.defaultBlockState())
|| blockState == Blocks.CAVE_AIR.defaultBlockState()
|| blockState == Blocks.BARRIER.defaultBlockState())
{
return 0;
}
@@ -664,7 +636,7 @@ public class LodBuilder
blockColor = getColorTextureForBlock(blockState, blockPos, true);
//if the blockColor is 0 we reset it and don't use the faceColor
if(blockColor == 0)
if (blockColor == 0)
{
tintColor.remove(blockState.getBlock());
toTint.remove(blockState.getBlock());
@@ -672,8 +644,8 @@ public class LodBuilder
blockColor = getColorTextureForBlock(blockState, blockPos, false);
}
//if the blockColor is still 0 we use use the default materia color
if(blockColor == 0)
//if the blockColor is still 0 we use the default material color
if (blockColor == 0)
{
tintColor.replace(blockState.getBlock(), 0);
toTint.replace(blockState.getBlock(), false);
@@ -684,32 +656,22 @@ public class LodBuilder
{
int tintValue = 0;
if (useGrassTint(blockState.getBlock()))
{
// grass and green plants
tintValue = biome.getGrassColor(x, z);
}
else if (useWaterTint(blockState.getBlock()))
{
// water
tintValue = biome.getWaterColor();
}else
{
else
// leaves
tintValue = biome.getFoliageColor();
}
colorInt = ColorUtil.multiplyRGBcolors(tintValue | 0xFF000000, blockColor);
}
else
{
colorInt = blockColor;
}
//colorInt = blockColor;
return colorInt;
}
/**
* Returns a color int for the given biome.
*/
/** Returns a color int for the given biome. */
private int getColorForBiome(int x, int z, Biome biome)
{
int colorInt;
@@ -772,9 +734,7 @@ public class LodBuilder
public static final ConcurrentMap<Block, Boolean> notFullBlock = new ConcurrentHashMap<>();
public static final ConcurrentMap<Block, Boolean> smallBlock = new ConcurrentHashMap<>();
/**
* Is the block at the given blockPos a valid LOD point?
*/
/** Is the block at the given blockPos a valid LOD point? */
private boolean isLayerValidLodPoint(IChunk chunk, BlockPos.Mutable blockPos)
{
BlockState blockState = chunk.getBlockState(blockPos);
@@ -25,7 +25,6 @@ import com.seibel.lod.enums.DistanceGenerationMode;
* Generally this will only be used if we want to generate a
* LodChunk using an incomplete Chunk, otherwise the defaults
* work best for a fully generated chunk (IE has correct surface blocks).
*
* @author James Seibel
* @version 8-14-2021
*/
@@ -56,10 +55,10 @@ public class LodBuilderConfig
}
/**
* @param newUseHeightmap default = false
* @param newUseBiomeColors default = false
* @param newUseHeightmap default = false
* @param newUseBiomeColors default = false
* @param newUseSolidBlocksInBiomeColor default = true
* @param newDistanceGenerationMode default = Server
* @param newDistanceGenerationMode default = Server
*/
public LodBuilderConfig(boolean newUseHeightmap, boolean newUseBiomeColors,
boolean newUseSolidBlocksInBiomeColor, DistanceGenerationMode newDistanceGenerationMode)
@@ -71,8 +70,8 @@ public class LodBuilderConfig
}
/**
* @param newUseHeightmap default = false
* @param newUseBiomeColors default = false
* @param newUseHeightmap default = false
* @param newUseBiomeColors default = false
* @param newUseSolidBlocksInBiomeColor default = true
*/
public LodBuilderConfig(boolean newUseHeightmap, boolean newUseBiomeColors, boolean newUseSolidBlocksInBiomeColor)
@@ -85,7 +84,7 @@ public class LodBuilderConfig
}
/**
* @param newDistanceGenerationMode default = Server
* @param newDistanceGenerationMode default = Server
*/
public LodBuilderConfig(DistanceGenerationMode newDistanceGenerationMode)
{
@@ -59,7 +59,6 @@ import java.util.function.Supplier;
/**
* This is used to generate a LodChunk at a given ChunkPos.
*
* @author James Seibel
* @version 9-7-2021
*/
@@ -71,9 +70,11 @@ public class LodNodeGenWorker implements IWorker
private final LodChunkGenThread thread;
/** If a configured feature fails for whatever reason,
/**
* If a configured feature fails for whatever reason,
* add it to this list, this is to hopefully remove any
* features that could cause issues down the line. */
* features that could cause issues down the line.
*/
private static final ConcurrentHashMap<Integer, ConfiguredFeature<?, ?>> configuredFeaturesToAvoid = new ConcurrentHashMap<>();
@@ -384,7 +385,7 @@ public class LodNodeGenWorker implements IWorker
/**
* takes about 15 - 20 ms
*
* <p>
* Causes concurrentModification Exceptions,
* which could cause instability or world generation bugs
*/
@@ -506,9 +507,9 @@ public class LodNodeGenWorker implements IWorker
/**
* on pre generated chunks 0 - 1 ms
* on un generated chunks 0 - 50 ms
* with the median seeming to hover around 15 - 30 ms
* and outliers in the 100 - 200 ms range
*
* with the median seeming to hover around 15 - 30 ms
* and outliers in the 100 - 200 ms range
* <p>
* Note this should not be multithreaded and does cause server/simulation lag
* (Higher lag for generating than loading)
*/
@@ -606,7 +607,7 @@ public class LodNodeGenWorker implements IWorker
/**
* Stops the current genThreads if they are running
* and then recreates the Executor service. <br><br>
*
* <p>
* This is done to clear any outstanding tasks
* that may exist after the player leaves their current world.
* If this isn't done unfinished tasks may be left in the queue
@@ -15,16 +15,10 @@
* 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.builders.worldGeneration;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.function.Predicate;
import java.util.stream.Stream;
import com.seibel.lod.util.LodUtil;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
@@ -40,11 +34,7 @@ import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.SectionPos;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.DimensionType;
import net.minecraft.world.EmptyTickList;
import net.minecraft.world.ISeedReader;
import net.minecraft.world.ITickList;
import net.minecraft.world.*;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeManager;
import net.minecraft.world.border.WorldBorder;
@@ -59,272 +49,277 @@ import net.minecraft.world.lighting.WorldLightManager;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.IWorldInfo;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* This is a fake ServerWorld used when generating features.
* This allows us to keep each LodChunk generation independent
* of the actual ServerWorld, allowing us
* to multithread generation.
*
* @author James Seibel
* @version 7-26-2021
*/
public class LodServerWorld implements ISeedReader
{
public HashMap<Heightmap.Type, Heightmap> heightmaps = new HashMap<>();
public final IChunk chunk;
public final ServerWorld serverWorld;
public LodServerWorld(ServerWorld newServerWorld, IChunk newChunk)
{
chunk = newChunk;
serverWorld = newServerWorld;
}
@Override
public int getHeight(Type heightmapType, int x, int z)
{
// make sure the block position is set relative to the chunk
x = x % LodUtil.CHUNK_WIDTH;
x = (x < 0) ? x + 16 : x;
z = z % LodUtil.CHUNK_WIDTH;
z = (z < 0) ? z + 16 : z;
return chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(x, z);
}
@Override
public Biome getBiome(BlockPos pos)
{
return chunk.getBiomes().getNoiseBiome(pos.getX() >> 2, pos.getY() >> 2, pos.getZ() >> 2);
}
@Override
public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft)
{
return chunk.setBlockState(pos, state, false) == state;
}
@Override
public BlockState getBlockState(BlockPos pos)
{
return chunk.getBlockState(pos);
}
@Override
public FluidState getFluidState(BlockPos pos)
{
return chunk.getFluidState(pos);
}
@Override
public boolean isStateAtPosition(BlockPos pos, Predicate<BlockState> state)
{
return state.test(chunk.getBlockState(pos));
}
@Override
public ITickList<Block> getBlockTicks()
{
return EmptyTickList.empty();
}
@Override
public IChunk getChunk(int x, int z, ChunkStatus requiredStatus, boolean nonnull)
{
return chunk;
}
@Override
public Stream<? extends StructureStart<?>> startsForFeature(SectionPos p_241827_1_, Structure<?> p_241827_2_)
{
return serverWorld.startsForFeature(p_241827_1_, p_241827_2_);
}
@Override
public ITickList<Fluid> getLiquidTicks()
{
return EmptyTickList.empty();
}
@Override
public WorldLightManager getLightEngine()
{
return new WorldLightManager(null, false, false);
}
@Override
public long getSeed()
{
return serverWorld.getSeed();
}
@Override
public DynamicRegistries registryAccess()
{
return serverWorld.registryAccess();
}
/**
* All methods below shouldn't be needed
* and thus have been left unimplemented.
*/
@Override
public Random getRandom()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public void playSound(PlayerEntity player, BlockPos pos, SoundEvent soundIn, SoundCategory category, float volume,
float pitch)
float pitch)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public void addParticle(IParticleData particleData, double x, double y, double z, double xSpeed, double ySpeed,
double zSpeed)
double zSpeed)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public BiomeManager getBiomeManager()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public int getSeaLevel()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public float getShade(Direction p_230487_1_, boolean p_230487_2_)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public WorldBorder getWorldBorder()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public boolean removeBlock(BlockPos pos, boolean isMoving)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public boolean destroyBlock(BlockPos pos, boolean dropBlock, Entity entity, int recursionLeft)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public ServerWorld getLevel()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public AbstractChunkProvider getChunkSource()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public DifficultyInstance getCurrentDifficultyAt(BlockPos arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public IWorldInfo getLevelData()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public void levelEvent(PlayerEntity arg0, int arg1, BlockPos arg2, int arg3)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public List<Entity> getEntities(Entity arg0, AxisAlignedBB arg1, Predicate<? super Entity> arg2)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public <T extends Entity> List<T> getEntitiesOfClass(Class<? extends T> arg0, AxisAlignedBB arg1,
Predicate<? super T> arg2)
Predicate<? super T> arg2)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public List<? extends PlayerEntity> players()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public int getSkyDarken()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public Biome getUncachedNoiseBiome(int p_225604_1_, int p_225604_2_, int p_225604_3_)
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public boolean isClientSide()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public DimensionType dimensionType()
{
throw new UnsupportedOperationException("Not Implemented");
}
@Override
public TileEntity getBlockEntity(BlockPos p_175625_1_)
{
throw new UnsupportedOperationException("Not Implemented");
}
}
@@ -1,11 +1,5 @@
package com.seibel.lod.builders.worldGeneration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.seibel.lod.builders.lodBuilding.LodBuilder;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
@@ -17,14 +11,18 @@ import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.WorldWorkerManager;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A singleton that handles all long distance LOD world generation.
*
* @author James Seibel
* @version 9-25-2021
*/
@@ -69,9 +67,8 @@ public class LodWorldGenerator
/**
* Queues up LodNodeGenWorkers for the given lodDimension.
*
* @param renderer needed so the LodNodeGenWorkers can flag that the
* buffers need to be rebuilt.
* buffers need to be rebuilt.
*/
public void queueGenerationRequests(LodDimension lodDim, LodRenderer renderer, LodBuilder lodBuilder)
{
@@ -104,19 +101,19 @@ public class LodWorldGenerator
maxChunkGenRequests,
playerPosX,
playerPosZ);
byte detailLevel;
int posX;
int posZ;
int nearIndex = 0;
int farIndex = 0;
for (int i = 0; i < posToGenerate.getNumberOfPos(); i++)
{
// I wish there was a way to compress this code, but I'm not aware of
// an easy way to do so.
// add the near positions
if (posToGenerate.getNthDetail(nearIndex, true) != 0 && nearIndex < posToGenerate.getNumberOfNearPos())
{
@@ -126,11 +123,11 @@ public class LodWorldGenerator
nearIndex++;
ChunkPos chunkPos = new ChunkPos(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ));
// prevent generating the same chunk multiple times
if (positionsWaitingToBeGenerated.contains(chunkPos))
continue;
// don't add more to the generation queue then allowed
if (numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests)
break;
@@ -140,8 +137,8 @@ public class LodWorldGenerator
LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, DetailDistanceUtil.getDistanceGenerationMode(detailLevel), lodBuilder, lodDim, serverWorld);
WorldWorkerManager.addWorker(genWorker);
}
// add the far positions
if (posToGenerate.getNthDetail(farIndex, false) != 0 && farIndex < posToGenerate.getNumberOfFarPos())
{
@@ -151,16 +148,16 @@ public class LodWorldGenerator
farIndex++;
ChunkPos chunkPos = new ChunkPos(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ));
// don't add more to the generation queue then allowed
if (numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests)
continue;
//break;
//break;
// prevent generating the same chunk multiple times
if (positionsWaitingToBeGenerated.contains(chunkPos))
continue;
positionsWaitingToBeGenerated.add(chunkPos);
numberOfChunksWaitingToGenerate.addAndGet(1);
LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, DetailDistanceUtil.getDistanceGenerationMode(detailLevel), lodBuilder, lodDim, serverWorld);
@@ -18,38 +18,23 @@
package com.seibel.lod.config;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.core.io.WritingMode;
import com.seibel.lod.ModInfo;
import com.seibel.lod.enums.BufferRebuildTimes;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.enums.DetailDropOff;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.FogDistance;
import com.seibel.lod.enums.FogDrawOverride;
import com.seibel.lod.enums.GenerationPriority;
import com.seibel.lod.enums.HorizontalQuality;
import com.seibel.lod.enums.HorizontalResolution;
import com.seibel.lod.enums.HorizontalScale;
import com.seibel.lod.enums.LodTemplate;
import com.seibel.lod.enums.VanillaOverdraw;
import com.seibel.lod.enums.VerticalQuality;
import com.seibel.lod.enums.*;
import com.seibel.lod.util.LodUtil;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* This handles any configuration the user has access to.
*
* @author James Seibel
* @version 10-11-2021
*/
@@ -15,6 +15,7 @@
* 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.enums;
/**
@@ -22,22 +23,21 @@ package com.seibel.lod.enums;
* Far_First <br>
* <br>
* Determines how fast the buffers need to be regenerated
*
* @author Leonardo Amato
* @version 9-25-2021
*/
public enum BufferRebuildTimes
{
FREQUENT(1000, 500, 2500),
NORMAL(2000, 1000, 5000),
RARE(5000, 2000, 10000);
public final int playerMoveTimeout;
public final int renderedChunkTimeout;
public final int chunkChangeTimeout;
BufferRebuildTimes(int playerMoveTimeout, int renderedChunkTimeout, int chunkChangeTimeout)
{
this.playerMoveTimeout = playerMoveTimeout;
@@ -15,11 +15,11 @@
* 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.enums;
/**
* off, detail, detail wireframe
*
* @author James Seibel
* @version 8-28-2021
*/
@@ -36,7 +36,8 @@ public enum DebugMode
/** used when cycling through the different modes */
private DebugMode next;
static
static
{
OFF.next = SHOW_DETAIL;
SHOW_DETAIL.next = SHOW_DETAIL_WIREFRAME;
@@ -15,13 +15,13 @@
* 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.enums;
/**
* By_Region_Fast, <br>
* By_Region_Fancy, <br>
* By_Chunk
*
* @author Leonardo Amato
* @version 9-25-2021
*/
@@ -29,7 +29,7 @@ public enum DetailDropOff
{
/** quality is determined per-region, using the lowest quality that would be used in BY_CHUNK */
FAST,
/** quality is determined per-block (the best quality option, may cause stuttering when moving) */
FANCY,
}
@@ -15,6 +15,7 @@
* 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.enums;
/**
@@ -26,7 +27,6 @@ package com.seibel.lod.enums;
* SERVER <br><br>
* <p>
* In order of fastest to slowest.
*
* @author James Seibel
* @author Leonardo Amato
* @version 8-7-2021
@@ -37,7 +37,7 @@ public enum DistanceGenerationMode
* Don't generate anything
*/
NONE((byte) 0),
/**
* Only generate the biomes and use biome
* grass/foliage color, water color, or ice color
@@ -46,7 +46,7 @@ public enum DistanceGenerationMode
* Multithreaded - Fastest (2-5 ms)
*/
BIOME_ONLY((byte) 1),
/**
* Same as BIOME_ONLY, except instead
* of always using sea level as the LOD height
@@ -54,7 +54,7 @@ public enum DistanceGenerationMode
* use predetermined heights to simulate having height data.
*/
BIOME_ONLY_SIMULATE_HEIGHT((byte) 2),
/**
* Generate the world surface,
* this does NOT include caves, trees,
@@ -62,7 +62,7 @@ public enum DistanceGenerationMode
* Multithreaded - Faster (10-20 ms)
*/
SURFACE((byte) 3),
/**
* Generate everything except structures.
* NOTE: This may cause world generation bugs or instability,
@@ -70,7 +70,7 @@ public enum DistanceGenerationMode
* Multithreaded - Fast (15-20 ms)
*/
FEATURES((byte) 4),
/**
* Ask the server to generate/load each chunk.
* This is the most compatible, but causes server/simulation lag.
@@ -79,13 +79,13 @@ public enum DistanceGenerationMode
* Singlethreaded - Slow (15-50 ms, with spikes up to 200 ms)
*/
SERVER((byte) 5);
/**
* The higher the number the more complete the generation is.
*/
public final byte complexity;
DistanceGenerationMode(byte complexity)
{
this.complexity = complexity;
@@ -15,11 +15,11 @@
* 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.enums;
/**
* NEAR, FAR, or NEAR_AND_FAR.
*
* @author James Seibel
* @version 02-14-2021
*/
@@ -32,5 +32,5 @@ public enum FogDistance
FAR,
/** only looks good if the fog quality is set to Fancy. */
NEAR_AND_FAR;
NEAR_AND_FAR
}
@@ -15,6 +15,7 @@
* 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.enums;
/**
@@ -22,14 +23,15 @@ package com.seibel.lod.enums;
* NEVER_DRAW_FOG, <br>
* ALWAYS_DRAW_FOG_FAST, <br>
* ALWAYS_DRAW_FOG_FANCY <br>
*
* @author James Seibel
* @version 7-3-2021
*/
public enum FogDrawOverride
{
/** Use whatever Fog setting optifine is using.
* If optifine isn't installed this defaults to ALWAYS_DRAW_FOG. */
/**
* Use whatever Fog setting optifine is using.
* If optifine isn't installed this defaults to ALWAYS_DRAW_FOG.
*/
USE_OPTIFINE_FOG_SETTING,
/** Never draw fog on the LODs */
@@ -39,5 +41,5 @@ public enum FogDrawOverride
ALWAYS_DRAW_FOG_FAST,
/** Always draw fog on the LODs */
ALWAYS_DRAW_FOG_FANCY;
ALWAYS_DRAW_FOG_FANCY
}
@@ -15,11 +15,11 @@
* 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.enums;
/**
* fast, fancy, or off
*
* @author James Seibel
* @version 02-14-2021
*/
@@ -27,5 +27,5 @@ public enum FogQuality
{
FAST,
FANCY,
OFF;
OFF
}
@@ -15,6 +15,7 @@
* 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.enums;
/**
@@ -23,7 +24,6 @@ package com.seibel.lod.enums;
* <br>
* Determines which LODs should have priority when generating
* outside the normal view distance.
*
* @author Leonardo Amato
* @version 9-25-2021
*/
@@ -31,5 +31,5 @@ public enum GenerationPriority
{
NEAR_FIRST,
FAR_FIRST;
FAR_FIRST
}
@@ -1,8 +1,7 @@
package com.seibel.lod.enums;
/**
/**
* Minecraft, Lod_Builder, None
*
* @author James Seibel
* @version 10-1-2021
*/
@@ -15,6 +15,7 @@
* 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.enums;
/**
@@ -23,7 +24,6 @@ package com.seibel.lod.enums;
* High <br>
* <br>
* this indicates the base of the quadratic function we use for the quality drop off
*
* @author Leonardo Amato
* @version 9-29-2021
*/
@@ -31,18 +31,18 @@ public enum HorizontalQuality
{
/** Lods are 2D with heightMap */
LINEAR(1.0f),
/** Lods are 2D with heightMap */
LOW(1.5f),
/** Lods expand in three dimension */
MEDIUM(2.0f),
/** Lods expand in three dimension */
HIGH(2.2f);
public final double quadraticBase;
HorizontalQuality(double distanceUnit)
{
this.quadraticBase = distanceUnit;
@@ -15,20 +15,20 @@
* 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.enums;
import com.seibel.lod.util.LodUtil;
import java.util.ArrayList;
import java.util.Collections;
import com.seibel.lod.util.LodUtil;
/**
* chunk <Br>
* half_chunk <Br>
* four_blocks <br>
* two_blocks <Br>
* block <br>
*
* @author James Seibel
* @author Leonardo Amato
* @version 9-25-2021
@@ -49,16 +49,20 @@ public enum HorizontalResolution
/** render 256 LODs for each chunk */
BLOCK(16, 0);
/** How many DataPoints should
* be drawn per side, per LodChunk */
/**
* How many DataPoints should
* be drawn per side, per LodChunk
*/
public final int dataPointLengthCount;
/** How wide each LOD DataPoint is */
public final int dataPointWidth;
/** This is the same as detailLevel in LodQuadTreeNode,
* lowest is 0 highest is 9 */
/**
* This is the same as detailLevel in LodQuadTreeNode,
* lowest is 0 highest is 9
*/
public final byte detailLevel;
/* Start/End X/Z give the block positions
@@ -68,19 +72,19 @@ public enum HorizontalResolution
public final int[] endX;
public final int[] endZ;
/**
/**
* 1st dimension: LodDetail.detailLevel <br>
* 2nd dimension: An array of all LodDetails that are less than or <br>
* equal to that detailLevel
* equal to that detailLevel
*/
private static HorizontalResolution[][] lowerDetailArrays;
private HorizontalResolution(int newLengthCount, int newDetailLevel)
HorizontalResolution(int newLengthCount, int newDetailLevel)
{
detailLevel = (byte) newDetailLevel;
dataPointLengthCount = newLengthCount;
@@ -94,15 +98,15 @@ public enum HorizontalResolution
int index = 0;
for(int x = 0; x < newLengthCount; x++)
for (int x = 0; x < newLengthCount; x++)
{
for(int z = 0; z < newLengthCount; z++)
for (int z = 0; z < newLengthCount; z++)
{
startX[index] = x * dataPointWidth;
startZ[index] = z * dataPointWidth;
endX[index] = (x*dataPointWidth) + dataPointWidth;
endZ[index] = (z*dataPointWidth) + dataPointWidth;
endX[index] = (x * dataPointWidth) + dataPointWidth;
endZ[index] = (z * dataPointWidth) + dataPointWidth;
index++;
}
@@ -115,7 +119,7 @@ public enum HorizontalResolution
/**
/**
* Returns an array of all LodDetails that have a detail level
* that is less than or equal to the given LodDetail
*/
@@ -127,12 +131,12 @@ public enum HorizontalResolution
lowerDetailArrays = new HorizontalResolution[HorizontalResolution.values().length][];
// go through each LodDetail
for(HorizontalResolution currentDetail : HorizontalResolution.values())
for (HorizontalResolution currentDetail : HorizontalResolution.values())
{
ArrayList<HorizontalResolution> lowerDetails = new ArrayList<>();
// find the details lower than currentDetail
for(HorizontalResolution compareDetail : HorizontalResolution.values())
for (HorizontalResolution compareDetail : HorizontalResolution.values())
{
if (currentDetail.detailLevel <= compareDetail.detailLevel)
{
@@ -15,6 +15,7 @@
* 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.enums;
/**
@@ -23,7 +24,6 @@ package com.seibel.lod.enums;
* High <br>
* <br>
* this is a quality scale for the detail drop-off
*
* @author Leonardo Amato
* @version 9-25-2021
*/
@@ -15,6 +15,7 @@
* 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.enums;
import com.seibel.lod.builders.bufferBuilding.lodTemplates.AbstractLodTemplate;
@@ -24,29 +25,34 @@ import com.seibel.lod.builders.bufferBuilding.lodTemplates.TriangularLodTemplate
/**
* Cubic, Triangular, Dynamic
*
* @author James Seibel
* @version 10-10-2021
*/
public enum LodTemplate
{
/** LODs are rendered as
* rectangular prisms. */
/**
* LODs are rendered as
* rectangular prisms.
*/
CUBIC(new CubicLodTemplate()),
/** LODs smoothly transition between
* each other. */
/**
* LODs smoothly transition between
* each other.
*/
TRIANGULAR(new TriangularLodTemplate()),
/** LODs smoothly transition between
/**
* LODs smoothly transition between
* each other, unless a neighboring LOD
* is at a significantly different height. */
* is at a significantly different height.
*/
DYNAMIC(new DynamicLodTemplate());
public final AbstractLodTemplate template;
private LodTemplate(AbstractLodTemplate newTemplate)
LodTemplate(AbstractLodTemplate newTemplate)
{
template = newTemplate;
}
@@ -2,7 +2,6 @@ package com.seibel.lod.enums;
/**
* NONE, GAME_SHADING
*
* @author James Seibel
* @version 7-25-2020
*/
@@ -15,8 +14,8 @@ public enum ShadingMode
NONE,
/**
* LODs will have darker sides and bottoms to simulate
* LODs will have darker sides and bottoms to simulate
* Minecraft's fast, top down lighting.
*/
GAME_SHADING;
GAME_SHADING
}
@@ -1,12 +1,11 @@
package com.seibel.lod.enums;
/**
/**
* None, Dynamic, Always
*
*
* <p>
* This represents how far the LODs should overlap with
* the vanilla Minecraft terrain.
*
* @author James Seibel
* @version 10-11-2021
*/
@@ -15,19 +15,19 @@
* 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.enums;
/**
* heightmap <br>
* multi_lod <br>
*
* @author Leonardo Amato
* @version 10-07-2021
*/
public enum VerticalQuality
{
LOW(
new int[]{2,
new int[] { 2,
2,
2,
2,
@@ -37,11 +37,11 @@ public enum VerticalQuality
1,
1,
1,
1}
1 }
),
MEDIUM(
new int[]{4,
new int[] { 4,
4,
2,
2,
@@ -51,11 +51,11 @@ public enum VerticalQuality
1,
1,
1,
1}
1 }
),
HIGH(
new int[]{
new int[] {
8,
8,
4,
@@ -66,7 +66,7 @@ public enum VerticalQuality
1,
1,
1,
1}
1 }
);
public final int[] maxVerticalData;
@@ -38,7 +38,6 @@ import java.util.concurrent.Executors;
* This object handles creating LodRegions
* from files and saving LodRegion objects
* to file.
*
* @author James Seibel
* @author Cola
* @version 9-25-2021
@@ -130,14 +129,20 @@ public class LodDimensionFileHandler
if (fileName != null)
{
file = new File(fileName);
if (file.exists()) break;
if (file.exists())
break;
}
//decrease gen mode
if (tempGenMode == DistanceGenerationMode.SERVER) tempGenMode = DistanceGenerationMode.FEATURES;
else if (tempGenMode == DistanceGenerationMode.FEATURES) tempGenMode = DistanceGenerationMode.SURFACE;
else if (tempGenMode == DistanceGenerationMode.SURFACE) tempGenMode = DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT;
else if (tempGenMode == DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT) tempGenMode = DistanceGenerationMode.BIOME_ONLY;
else if (tempGenMode == DistanceGenerationMode.BIOME_ONLY) tempGenMode = DistanceGenerationMode.NONE;
if (tempGenMode == DistanceGenerationMode.SERVER)
tempGenMode = DistanceGenerationMode.FEATURES;
else if (tempGenMode == DistanceGenerationMode.FEATURES)
tempGenMode = DistanceGenerationMode.SURFACE;
else if (tempGenMode == DistanceGenerationMode.SURFACE)
tempGenMode = DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT;
else if (tempGenMode == DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT)
tempGenMode = DistanceGenerationMode.BIOME_ONLY;
else if (tempGenMode == DistanceGenerationMode.BIOME_ONLY)
tempGenMode = DistanceGenerationMode.NONE;
}
if (!file.exists())
//there wasn't a file, don't return anything
@@ -200,7 +205,7 @@ public class LodDimensionFileHandler
ClientProxy.LOGGER.error("LOD file read error. Unable to read to [" + fileName + "] error [" + ioEx.getMessage() + "]: ");
ioEx.printStackTrace();
}
}// file datasize > 0
}
}
catch (Exception e)
{
@@ -29,7 +29,6 @@ import java.lang.reflect.Method;
* This object is used to get variables from methods
* where they are private. Specifically the fog setting
* in Optifine.
*
* @author James Seibel
* @version 9-25-2021
*/
@@ -106,10 +105,8 @@ public class ReflectionHandler
case 0:
// optifine's "default" option,
// it should never be called in this case
return FogQuality.FAST;
// normal options
// normal options
case 1:
return FogQuality.FAST;
case 2:
@@ -34,7 +34,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* If this wasn't done, and we used Forge's
* render last event, the LODs would render on top
* of the normal terrain.
*
* @author James Seibel
* @version 9-19-2021
*/
@@ -5,8 +5,8 @@ package com.seibel.lod.objects;
*/
public interface LevelContainer
{
/**With this you can add data to the level container
*
/**
* 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
@@ -15,8 +15,8 @@ public interface LevelContainer
*/
boolean addData(long data, int posX, int posZ, int index);
/**With this you can add data to the level container
*
/**
* 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
@@ -24,16 +24,16 @@ public interface LevelContainer
*/
boolean addSingleData(long data, int posX, int posZ);
/**With this you can get data from the level container
*
/**
* 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
*
/**
* 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
@@ -58,14 +58,14 @@ public interface LevelContainer
/** 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.
/**
* 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
@@ -18,28 +18,23 @@
package com.seibel.lod.objects;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.GenerationPriority;
import com.seibel.lod.enums.VerticalQuality;
import com.seibel.lod.handlers.LodDimensionFileHandler;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.*;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.DimensionType;
import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* This object holds all loaded LOD regions
@@ -48,7 +43,6 @@ import net.minecraft.world.server.ServerWorld;
* <strong>Coordinate Standard: </strong><br>
* Coordinate called posX or posZ are relative LevelPos coordinates <br>
* unless stated otherwise. <br>
*
* @author Leonardo Amato
* @author James Seibel
* @version 10-10-2021
@@ -92,7 +86,6 @@ public class LodDimension
/**
* Creates the dimension centered at (0,0)
*
* @param newWidth in regions
*/
public LodDimension(DimensionType newDimension, LodWorld lodWorld, int newWidth)
@@ -294,7 +287,6 @@ public class LodDimension
/**
* Overwrite the LodRegion at the location of newRegion with newRegion.
*
* @throws ArrayIndexOutOfBoundsException if newRegion is outside what can be stored in this LodDimension.
*/
public synchronized void addOrOverwriteRegion(LodRegion newRegion) throws ArrayIndexOutOfBoundsException
@@ -597,7 +589,7 @@ public class LodDimension
/**
* Returns every node that should be rendered based on the position of the player.
*
* <p>
* TODO why isn't posToRender returned? it would make it a bit more clear what is happening
*/
public void getPosToRender(PosToRenderContainer posToRender, RegionPos regionPos, int playerPosX,
@@ -609,7 +601,7 @@ public class LodDimension
}
/**
* Determines how many vertical LODs could be used
* Determines how many vertical LODs could be used
* for the given region at the given detail level
*/
public int getMaxVerticalData(byte detailLevel, int posX, int posZ)
@@ -688,7 +680,7 @@ public class LodDimension
/**
* TODO we aren't currently using this, is there a reason for that?
* is this significantly different than regenRegionBuffer?
*
* <p>
* Returns if the buffer at the given array index needs
* to have its buffer resized.
*/
@@ -16,7 +16,6 @@ import com.seibel.lod.util.LodUtil;
* <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
*/
@@ -87,7 +86,6 @@ public class LodRegion
* Inserts the data point into the region.
* <p>
* TODO this will always return true unless it has
*
* @return true if the data was added successfully
*/
public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data)
@@ -109,7 +107,6 @@ public class LodRegion
/**
* 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.
*/
@@ -120,7 +117,6 @@ public class LodRegion
/**
* 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.
*/
@@ -434,7 +430,6 @@ public class LodRegion
/**
* Returns the LevelContainer for the detailLevel
*
* @throws IllegalArgumentException if the detailLevel is less than minDetailLevel
*/
public LevelContainer getLevel(byte detailLevel)
@@ -448,10 +443,9 @@ public class LodRegion
/**
* 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.
* is 2 or more detail levels lower than the
* minDetailLevel of this region.
*/
public void addLevelContainer(LevelContainer levelContainer)
{
@@ -26,7 +26,6 @@ import java.util.Map;
/**
* This stores all LODs for a given world.
*
* @author James Seibel
* @author Leonardo Amato
* @version 9-27-2021
@@ -57,10 +56,9 @@ public class LodWorld
/**
* Set up the LodWorld with the given newWorldName. <br>
* This should be done whenever loading a new world. <br><br>
*
* <p>
* Note a System.gc() call may be in order after calling this <Br>
* since a lot of LOD data is now homeless. <br>
*
* @param newWorldName name of the world
*/
public void selectWorld(String newWorldName)
@@ -85,7 +83,7 @@ public class LodWorld
* Set the worldName to "No world loaded"
* and clear the lodDimensions Map. <br>
* This should be done whenever unloaded a world. <br><br>
*
* <p>
* Note a System.gc() call may be in order after calling this <Br>
* since a lot of LOD data is now homeless. <br>
*/
@@ -152,9 +150,9 @@ public class LodWorld
}
public boolean getIsWorldLoaded()
public boolean getIsWorldNotLoaded()
{
return isWorldLoaded;
return !isWorldLoaded;
}
public String getWorldName()
@@ -24,7 +24,6 @@ import com.seibel.lod.enums.FogQuality;
/**
* This object is just a replacement for an array
* to make things easier to understand in the LodRenderer.
*
* @author James Seibel
* @version 7-03-2021
*/
@@ -33,8 +32,10 @@ public class NearFarFogSettings
public final NearOrFarSetting near = new NearOrFarSetting(FogDistance.NEAR);
public final NearOrFarSetting far = new NearOrFarSetting(FogDistance.FAR);
/** If true that means Minecraft is
* rendering fog alongside us */
/**
* If true that means Minecraft is
* rendering fog alongside us
*/
public boolean vanillaIsRenderingFog = true;
public NearFarFogSettings()
@@ -5,7 +5,6 @@ import com.seibel.lod.util.LevelPosUtil;
/**
* Holds the levelPos that need to be generated.
* TODO is that correct?
*
* @author Leonardo Amato
* @version 9-27-2021
*/
@@ -7,7 +7,6 @@ import com.seibel.lod.util.LodUtil;
import java.util.Arrays;
/**
*
* @author Leonardo Amato
* @version 9-18-2021
*/
@@ -20,7 +19,7 @@ public class PosToRenderContainer
private int numberOfPosToRender;
private int[] posToRender;
/*TODO this population matrix could be converted to boolean to improve memory use
* no since bools are stored as bytes anyway - cola*/
* no since bools are stored as bytes anyway - cola*/
private byte[][] population;
public PosToRenderContainer(byte minDetail, int regionPosX, int regionPosZ)
@@ -61,14 +60,10 @@ public class PosToRenderContainer
public boolean contains(byte detailLevel, int posX, int posZ)
{
if (LevelPosUtil.getRegion(detailLevel, posX) == regionPosX && LevelPosUtil.getRegion(detailLevel, posZ) == regionPosZ)
{
return (population[LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel, posX, minDetail))]
[LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel, posZ, minDetail))] == (detailLevel + 1));
}
else
{
return false;
}
}
public void clear(byte minDetail, int regionPosX, int regionPosZ)
@@ -15,16 +15,15 @@
* 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.objects;
import com.seibel.lod.util.LodUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
/**
* This object is similar to ChunkPos or BlockPos.
*
* @author James Seibel
* @version 8-21-2021
*/
@@ -36,7 +35,7 @@ public class RegionPos
/**
* Default Constructor <br><br>
*
* <p>
* Sets x and z to 0
*/
public RegionPos()
@@ -69,7 +68,7 @@ public class RegionPos
public ChunkPos chunkPos()
{
return new ChunkPos(
(x * LodUtil.REGION_WIDTH_IN_CHUNKS) + LodUtil.REGION_WIDTH_IN_CHUNKS / 2,
(x * LodUtil.REGION_WIDTH_IN_CHUNKS) + LodUtil.REGION_WIDTH_IN_CHUNKS / 2,
(z * LodUtil.REGION_WIDTH_IN_CHUNKS) + LodUtil.REGION_WIDTH_IN_CHUNKS / 2);
}
@@ -1,25 +1,18 @@
package com.seibel.lod.objects;
import com.seibel.lod.util.*;
import java.util.Arrays;
import com.seibel.lod.util.DataPointUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.ThreadMapUtil;
/**
* a VerticalLevelContainer is a quadTree level that can contain multiple voxel column per position.
*/
public class VerticalLevelContainer implements LevelContainer
{
public final byte detailLevel;
public final int size;
public final int maxVerticalData;
public final long[] dataContainer;
public VerticalLevelContainer(byte detailLevel)
{
this.detailLevel = detailLevel;
@@ -27,65 +20,74 @@ public class VerticalLevelContainer implements LevelContainer
maxVerticalData = DetailDistanceUtil.getMaxVerticalData(detailLevel);
dataContainer = new long[size * size * DetailDistanceUtil.getMaxVerticalData(detailLevel)];
}
@Override
public byte getDetailLevel()
{
return detailLevel;
}
@Override
public void clear(int posX, int posZ){
public void clear(int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for(int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++){
dataContainer[posX*size*maxVerticalData + posZ*maxVerticalData + verticalIndex] = DataPointUtil.EMPTY_DATA;
for (int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++)
{
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = DataPointUtil.EMPTY_DATA;
}
}
@Override
public boolean addData(long data, int posX, int posZ, int verticalIndex){
public boolean addData(long data, int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
dataContainer[posX*size*maxVerticalData + posZ*maxVerticalData + verticalIndex] = data;
dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex] = data;
return true;
}
@Override
public boolean addSingleData(long data, int posX, int posZ){
public boolean addSingleData(long data, int posX, int posZ)
{
return addData(data, posX, posZ, 0);
}
@Override
public long getData(int posX, int posZ, int verticalIndex){
public long getData(int posX, int posZ, int verticalIndex)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[posX*size*maxVerticalData + posZ*maxVerticalData + verticalIndex];
return dataContainer[posX * size * maxVerticalData + posZ * maxVerticalData + verticalIndex];
}
@Override
public long getSingleData(int posX, int posZ){
return getData(posX,posZ,0);
public long getSingleData(int posX, int posZ)
{
return getData(posX, posZ, 0);
}
@Override
public int getMaxVerticalData(){
public int getMaxVerticalData()
{
return maxVerticalData;
}
public int getSize(){
public int getSize()
{
return size;
}
@Override
public boolean doesItExist(int posX, int posZ){
public boolean doesItExist(int posX, int posZ)
{
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return DataPointUtil.doesItExist(getSingleData(posX,posZ));
return DataPointUtil.doesItExist(getSingleData(posX, posZ));
}
public VerticalLevelContainer(byte[] inputData)
{
int tempIndex;
@@ -100,7 +102,7 @@ public class VerticalLevelContainer implements LevelContainer
size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
int x = size * size * maxVerticalData;
this.dataContainer = new long[x];
for ( int i = 0; i < x; i++)
for (int i = 0; i < x; i++)
{
newData = 0;
if (counter > -1)
@@ -108,15 +110,17 @@ public class VerticalLevelContainer implements LevelContainer
dataContainer[i] = last;
if (last == 3)
{ //skip rest of void chunk
for (tempIndex = 1; tempIndex < maxVerticalData; tempIndex++) {
for (tempIndex = 1; tempIndex < maxVerticalData; tempIndex++)
{
dataContainer[i + tempIndex] = 0;
}
i += maxVerticalData - 1;
}
counter--;
} else if ((inputData[index] & 0x3) == 0 || (inputData[index] & 0x3) == 3)
}
else if ((inputData[index] & 0x3) == 0 || (inputData[index] & 0x3) == 3)
{
last = (byte)(inputData[index] & 0x3);
last = (byte) (inputData[index] & 0x3);
//recover counter
counter = (inputData[index] & 0x7c) >>> 2;
tempIndex = 0;
@@ -129,9 +133,11 @@ public class VerticalLevelContainer implements LevelContainer
index++;
//since loop expects from us to put some data in, we just make it rerun it with new counter;
i--;
} else if (index + 7 >= inputData.length)
}
else if (index + 7 >= inputData.length)
break;
else {
else
{
for (tempIndex = 0; tempIndex < 8; tempIndex++)
newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex);
index = index + 8;
@@ -139,19 +145,20 @@ public class VerticalLevelContainer implements LevelContainer
}
}
}
@Override
public LevelContainer expand(){
public LevelContainer expand()
{
return new VerticalLevelContainer((byte) (getDetailLevel() - 1));
}
@Override
public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ)
{
//We reset the array
long[] dataToMerge = ThreadMapUtil.getVerticalUpdateArray(detailLevel);
int lowerMaxVertical = dataToMerge.length/4;
int lowerMaxVertical = dataToMerge.length / 4;
int childPosX;
int childPosZ;
long[] data;
@@ -163,13 +170,13 @@ public class VerticalLevelContainer implements LevelContainer
{
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
for(int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++)
dataToMerge[(z*2+x)*lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
for (int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++)
dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex);
}
}
data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getMaxVerticalData());
for(int verticalIndex = 0; (verticalIndex < data.length) && (verticalIndex < maxVerticalData); verticalIndex++)
for (int verticalIndex = 0; (verticalIndex < data.length) && (verticalIndex < maxVerticalData); verticalIndex++)
{
addData(data[verticalIndex],
posX,
@@ -177,7 +184,7 @@ public class VerticalLevelContainer implements LevelContainer
verticalIndex);
}
}
@Override
public byte[] toDataString()
{
@@ -189,12 +196,12 @@ public class VerticalLevelContainer implements LevelContainer
long current;
byte[] tempData = ThreadMapUtil.getSaveContainer(2 + (x * 8));
tempData[index] = detailLevel;
index++;
tempData[index] = (byte) maxVerticalData;
index++;
for (int i = 0; i < x; i++)
{
current = dataContainer[i];
@@ -205,21 +212,23 @@ public class VerticalLevelContainer implements LevelContainer
if (current == 3) //skip rest of void chunk
i += maxVerticalData - 1;
counter++;
} else {
}
else
{
for (tempIndex = 0; tempIndex < 8; tempIndex++)
tempData[index + tempIndex] = (byte) (current >>> (8 * tempIndex));
index += 8;
}
if (last != -1 && ( i == x - 1 || last != ((dataContainer[i + 1]) & 0b11)))
if (last != -1 && (i == x - 1 || last != ((dataContainer[i + 1]) & 0b11)))
{ //save compressed data if next is different or if we reached onf of the data
tempData[index] = (byte)(0x7f & ((counter << 2) + last)); //save 5 bits of counter and compressed block
tempData[index] = (byte) (0x7f & ((counter << 2) + last)); //save 5 bits of counter and compressed block
tempIndex = 0;
while ((counter >>> (5 + 7 * tempIndex)) != 0) //there is more of that counter
{
tempData[index] = (byte)(tempData[index] | 0x80); //set overflow bit to true
tempData[index] = (byte) (tempData[index] | 0x80); //set overflow bit to true
index++; // after setting overflow bit w can actually index++
tempData[index] = (byte)(0x7f & (counter >>> (5 + 7 * tempIndex))); // save 7 bits of counter
tempData[index] = (byte) (0x7f & (counter >>> (5 + 7 * tempIndex))); // save 7 bits of counter
tempIndex++;
}
index++;
@@ -229,8 +238,9 @@ public class VerticalLevelContainer implements LevelContainer
}
return Arrays.copyOfRange(tempData, 0, index);
}
@Override
@SuppressWarnings("unused")
public String toString()
{
/*
@@ -251,10 +261,16 @@ public class VerticalLevelContainer implements LevelContainer
*/
return " ";
}
@Override
public int getMaxNumberOfLods(){
return size*size*getMaxVerticalData();
public int getMaxNumberOfLods()
{
return size * size * getMaxVerticalData();
}
@Override
public int getMaxMemoryUse()
{
return getMaxNumberOfLods() * 2; //2 byte
}
}
@@ -18,10 +18,6 @@
package com.seibel.lod.proxy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder;
import com.seibel.lod.builders.lodBuilding.LodBuilder;
@@ -38,7 +34,6 @@ import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.util.ThreadMapUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.profiler.IProfiler;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.client.event.InputEvent;
@@ -47,11 +42,13 @@ import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
/**
* This handles all events sent to the client,
* and is the starting point for most of the mod.
*
* @author James_Seibel
* @version 9-26-2021
*/
@@ -97,12 +94,7 @@ public class ClientProxy
// render event //
//==============//
/**
* Do any setup that is required to draw LODs
* and then tell the LodRenderer to draw.
*
* @param mcMatrixStack
*/
/** Do any setup that is required to draw LODs and then tell the LodRenderer to draw. */
public void renderLods(MatrixStack mcMatrixStack, float partialTicks)
{
// comment out when creating a release
@@ -118,7 +110,7 @@ public class ClientProxy
firstFrameSetup();
if (mc == null || mc.getPlayer() == null || !lodWorld.getIsWorldLoaded())
if (mc == null || mc.getPlayer() == null || lodWorld.getIsWorldNotLoaded())
return;
LodDimension lodDim = lodWorld.getLodDimension(mc.getCurrentDimension());
@@ -203,7 +195,7 @@ public class ClientProxy
@SubscribeEvent
public void serverTickEvent(TickEvent.ServerTickEvent event)
{
if (mc == null || mc.getPlayer() == null || !lodWorld.getIsWorldLoaded())
if (mc == null || mc.getPlayer() == null || lodWorld.getIsWorldNotLoaded())
return;
LodDimension lodDim = lodWorld.getLodDimension(mc.getPlayer().level.dimensionType());
@@ -12,12 +12,10 @@ import org.lwjgl.opengl.GLCapabilities;
*
* <p>
* Helpful OpenGL resources: <br><br>
*
* <p>
* https://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf <br>
* https://learnopengl.com/Advanced-OpenGL/Advanced-Data <br>
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br><br>
*
*
* @author James Seibel
* @version 10-2-2021
*/
@@ -35,8 +33,10 @@ public class GlProxy
/** the LodBuilder's GL context */
public final GLCapabilities lodBuilderGlCapabilities;
/** This is just used for debugging, hopefully it can be removed once
* the context switching is more stable. */
/**
* This is just used for debugging, hopefully it can be removed once
* the context switching is more stable.
*/
public Thread lodBuilderOwnerThread = null;
/** Does this computer's GPU support fancy fog? */
@@ -88,9 +88,7 @@ public class GlProxy
fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance;
if (!fancyFogAvailable)
{
ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that the fancy fog option will not be available.");
}
}
@@ -18,24 +18,13 @@
package com.seibel.lod.render;
import java.util.HashSet;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.NVFogDistance;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder;
import com.seibel.lod.builders.bufferBuilding.LodBufferBuilder.VertexBuffersAndOffset;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.enums.DetailDropOff;
import com.seibel.lod.enums.FogDistance;
import com.seibel.lod.enums.FogDrawOverride;
import com.seibel.lod.enums.FogQuality;
import com.seibel.lod.enums.*;
import com.seibel.lod.handlers.ReflectionHandler;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.NearFarFogSettings;
@@ -46,7 +35,6 @@ import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LevelPosUtil;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.GameRenderer;
@@ -57,12 +45,17 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.NVFogDistance;
import java.util.HashSet;
/**
* This is where all the magic happens. <br>
* This is where LODs are draw to the world.
*
* @author James Seibel
* @version 10-11-2021
*/
@@ -152,10 +145,9 @@ public class LodRenderer
/**
* Besides drawing the LODs this method also starts
* the async process of generating the Buffers that hold those LODs.
*
* @param lodDim The dimension to draw, if null doesn't replace the current dimension.
* @param lodDim The dimension to draw, if null doesn't replace the current dimension.
* @param mcMatrixStack This matrix stack should come straight from MC's renderChunkLayer (or future equivalent) method
* @param partialTicks how far into the current tick this method was called.
* @param partialTicks how far into the current tick this method was called.
*/
@SuppressWarnings("deprecation")
public void drawLODs(LodDimension lodDim, MatrixStack mcMatrixStack, float partialTicks, IProfiler newProfiler)
@@ -517,9 +509,8 @@ public class LodRenderer
/**
* create a new projection matrix and send it over to the GPU
*
* @param currentProjectionMatrix this is Minecraft's current projection matrix
* @param partialTicks how many ticks into the frame we are
* @param partialTicks how many ticks into the frame we are
*/
private void setupProjectionMatrix(Matrix4f currentProjectionMatrix, float partialTicks)
{
@@ -731,10 +722,6 @@ public class LodRenderer
switch (LodConfig.CLIENT.graphics.fogDistance.get())
{
case NEAR_AND_FAR:
fogSettings.near.distance = FogDistance.NEAR;
fogSettings.far.distance = FogDistance.NEAR;
break;
case NEAR:
fogSettings.near.distance = FogDistance.NEAR;
fogSettings.far.distance = FogDistance.NEAR;
@@ -748,14 +735,10 @@ public class LodRenderer
break;
case OFF:
fogSettings.near.quality = FogQuality.OFF;
fogSettings.far.quality = FogQuality.OFF;
break;
}
return fogSettings;
}
@@ -20,7 +20,6 @@ package com.seibel.lod.render;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.vector.Vector3d;
@@ -28,7 +27,6 @@ import net.minecraft.util.math.vector.Vector3d;
/**
* This holds miscellaneous helper code
* to be used in the rendering process.
*
* @author James Seibel
* @version 10-10-2021
*/
@@ -47,7 +45,7 @@ public class RenderUtil
&& pos.x <= center.x + mc.getRenderDistance())
&&
(pos.z >= center.z - mc.getRenderDistance()
&& pos.z <= center.z + mc.getRenderDistance());
&& pos.z <= center.z + mc.getRenderDistance());
}
/**
@@ -60,7 +58,7 @@ public class RenderUtil
&& x <= centerCoordinate + mc.getRenderDistance())
&&
(z >= centerCoordinate - mc.getRenderDistance()
&& z <= centerCoordinate + mc.getRenderDistance());
&& z <= centerCoordinate + mc.getRenderDistance());
}
@@ -76,7 +74,7 @@ public class RenderUtil
&& i <= lodRadius + halfRadius)
&&
(j >= lodRadius - halfRadius
&& j <= lodRadius + halfRadius);
&& j <= lodRadius + halfRadius);
}
@@ -8,57 +8,49 @@ public class ColorUtil
{
return (0xFF << 24) | (red << 16) | (green << 8) | blue;
}
public static int rgbToInt(int alpha, int red, int green, int blue)
{
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
public static int getAlpha(int color)
{
return (color >> 24) & 0xFF;
}
public static int getRed(int color)
{
return (color >> 16) & 0xFF;
}
public static int getGreen(int color)
{
return (color >> 8) & 0xFF;
}
public static int getBlue(int color)
{
return color & 0xFF;
}
public static int applyShade(int color, int shade)
{
if (shade < 0)
{
return (getAlpha(color) << 24) | (Math.max(getRed(color) + shade, 0) << 16) | (Math.max(getGreen(color) + shade, 0) << 8) | Math.max(getBlue(color) + shade, 0);
} else
{
else
return (getAlpha(color) << 24) | (Math.min(getRed(color) + shade, 255) << 16) | (Math.min(getGreen(color) + shade, 255) << 8) | Math.min(getBlue(color) + shade, 255);
}
}
public static int applyShade(int color, float shade)
{
if (shade < 1)
{
return (getAlpha(color) << 24) | ((int) Math.max(getRed(color) * shade, 0) << 16) | ((int) Math.max(getGreen(color) * shade, 0) << 8) | (int) Math.max(getBlue(color) * shade, 0);
} else
{
else
return (getAlpha(color) << 24) | ((int) Math.min(getRed(color) * shade, 255) << 16) | ((int) Math.min(getGreen(color) * shade, 255) << 8) | (int) Math.min(getBlue(color) * shade, 255);
}
}
/**
* Edit the given color as an HSV (Hue Saturation Value) color.
*/
/** Edit the given color as an HSV (Hue Saturation Value) color */
public static int applySaturationAndBrightnessMultipliers(int color, float saturationMultiplier, float brightnessMultiplier)
{
float[] hsv = Color.RGBtoHSB(getRed(color), getGreen(color), getBlue(color), null);
@@ -67,45 +59,19 @@ public class ColorUtil
LodUtil.clamp(0.0f, hsv[1] * saturationMultiplier, 1.0f),
LodUtil.clamp(0.0f, hsv[2] * brightnessMultiplier, 1.0f)).getRGB();
}
/**
* Edit the given color as an HSV (Hue Saturation Value) color.
*/
public static int changeBrightness(int color, float brightness)
{
float[] hsv = Color.RGBtoHSB(getRed(color), getGreen(color), getBlue(color), null);
return Color.getHSBColor(
hsv[0], // hue
hsv[1],
brightness).getRGB();
}
/**
* Edit the given color as an HSV (Hue Saturation Value) color.
*/
public static int changeBrightnessValue(int color, int brightnessColor)
{
float[] hsv = Color.RGBtoHSB(getRed(color), getGreen(color), getBlue(color), null);
float brightness = Color.RGBtoHSB(getRed(brightnessColor), getGreen(brightnessColor), getBlue(brightnessColor), null)[2];
return Color.getHSBColor(
hsv[0], // hue
hsv[1],
brightness).getRGB();
}
/** Multiply 2 RGB colors */
public static int multiplyRGBcolors(int color1, int color2)
{
return ((getAlpha(color1) * getAlpha(color2) / 255) << 24) | ((getRed(color1) * getRed(color2) / 255) << 16) | ((getGreen(color1) * getGreen(color2) / 255) << 8) | (getBlue(color1) * getBlue(color2) / 255);
}
@SuppressWarnings("unused")
public static String toString(int color)
{
return Integer.toHexString(getAlpha(color)) +
" " +
Integer.toHexString(getRed(color)) +
" " +
Integer.toHexString(getGreen(color)) +
" " +
return Integer.toHexString(getAlpha(color)) + " " +
Integer.toHexString(getRed(color)) + " " +
Integer.toHexString(getGreen(color)) + " " +
Integer.toHexString(getBlue(color));
}
}
@@ -173,7 +173,7 @@ public class DataPointUtil
{
return (int) (((dataPoint >>> COLOR_SHIFT) & COLOR_MASK) | (((dataPoint >>> (ALPHA_SHIFT - ALPHA_DOWNSIZE_SHIFT)) | 0b1111) << 24));
}
/** This method apply the lightmap to the color to use */
public static int getLightColor(long dataPoint, NativeImage lightMap)
{
@@ -186,8 +186,9 @@ public class DataPointUtil
return ColorUtil.multiplyRGBcolors(getColor(dataPoint), ColorUtil.rgbToInt(red, green, blue));
}
/** 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) + " " +
@@ -202,71 +203,6 @@ public class DataPointUtil
isVoid(dataPoint) + " " +
doesItExist(dataPoint) + '\n';
}
/**
* This method merge column of single data together
* @deprecated
*/
public static long mergeSingleData(long[] dataToMerge)
{
int numberOfChildren = 0;
int tempAlpha = 0;
int tempRed = 0;
int tempGreen = 0;
int tempBlue = 0;
int tempHeight = Integer.MIN_VALUE;
int tempDepth = Integer.MAX_VALUE;
int tempLightBlock = 0;
int tempLightSky = 0;
byte tempGenMode = DistanceGenerationMode.SERVER.complexity;
boolean allEmpty = true;
boolean allVoid = true;
for (long data : dataToMerge)
{
if (DataPointUtil.doesItExist(data))
{
allEmpty = false;
if (!(DataPointUtil.isVoid(data)))
{
numberOfChildren++;
allVoid = false;
tempAlpha += DataPointUtil.getAlpha(data);
tempRed += DataPointUtil.getRed(data);
tempGreen += DataPointUtil.getGreen(data);
tempBlue += DataPointUtil.getBlue(data);
tempHeight = Math.max(tempHeight, DataPointUtil.getHeight(data));
tempDepth = Math.min(tempDepth, DataPointUtil.getDepth(data));
tempLightBlock += DataPointUtil.getLightBlock(data);
tempLightSky += DataPointUtil.getLightSky(data);
}
tempGenMode = (byte) Math.min(tempGenMode, DataPointUtil.getGenerationMode(data));
} else
{
tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity);
}
}
if (allEmpty)
{
//no child has been initialized
return DataPointUtil.EMPTY_DATA;
} else if (allVoid)
{
//all the children are void
return DataPointUtil.createVoidDataPoint(tempGenMode);
} else
{
//we have at least 1 child
tempAlpha = tempAlpha / numberOfChildren;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempLightBlock = tempLightBlock / numberOfChildren;
tempLightSky = tempLightSky / numberOfChildren;
return DataPointUtil.createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, tempHeight, tempDepth, tempLightSky, tempLightBlock, tempGenMode);
}
}
public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize)
{
@@ -292,13 +228,13 @@ public class DataPointUtil
array[start + i] = 0;
}
}
/**
* 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 1 column of correctly parsed data
* @return one column of correctly parsed data
*/
public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData)
{
@@ -470,7 +406,7 @@ public class DataPointUtil
ii = worldHeight;
for (i = 0; i < count - 1; i++)
{
if (heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2]< ii)
if (heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2] < ii)
{
ii = heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2];
j = i;
@@ -493,7 +429,7 @@ public class DataPointUtil
if ((depth == 0 && height == 0) || j >= heightAndDepth.length / 2)
break;
int numberOfChildren = 0;
int tempAlpha = 0;
int tempRed = 0;
@@ -513,7 +449,7 @@ public class DataPointUtil
singleData = dataToMerge[index * inputVerticalData + dataIndex];
if (doesItExist(singleData) && !isVoid(singleData))
{
if ((depth <= getDepth(singleData) && getDepth(singleData) <= height)
|| (depth <= getHeight(singleData) && getHeight(singleData) <= height))
{
@@ -524,7 +460,8 @@ public class DataPointUtil
else
break;
}
if(!doesItExist(data)){
if (!doesItExist(data))
{
singleData = dataToMerge[index * inputVerticalData];
data = createVoidDataPoint(getGenerationMode(singleData));
}
@@ -17,20 +17,6 @@ public class DetailDistanceUtil
private static int maxDistance = LodConfig.CLIENT.graphics.lodChunkRenderDistance.get() * 16 * 2;
private static final int[] maxVerticalData = {
4,
4,
4,
2,
2,
1,
1,
1,
1,
1,
1 };
private static final HorizontalResolution[] lodGenDetails = {
HorizontalResolution.BLOCK,
HorizontalResolution.TWO_BLOCKS,
@@ -164,9 +164,7 @@ public class LevelPosUtil
boolean inXArea = playerPosX >= startPosX && playerPosX <= endPosX;
boolean inZArea = playerPosZ >= startPosZ && playerPosZ <= endPosZ;
if (inXArea && inZArea)
{
return 0;
}
else if (inXArea)
{
return Math.min(
@@ -221,9 +219,12 @@ public class LevelPosUtil
return compareResult;
}
@SuppressWarnings("unused")
public static String toString(int[] levelPos)
{
return (getDetailLevel(levelPos) + " " + getPosX(levelPos) + " " + getPosZ(levelPos));
return (getDetailLevel(levelPos) + " "
+ getPosX(levelPos) + " "
+ getPosZ(levelPos));
}
public static String toString(byte detailLevel, int posX, int posZ)
@@ -5,7 +5,6 @@ import java.util.concurrent.ThreadFactory;
/**
* Just a simple ThreadFactory to name ExecutorService
* threads, which can be helpful when debugging.
*
* @author James Seibel
* @version 8-15-2021
*/
@@ -22,7 +21,7 @@ public class LodThreadFactory implements ThreadFactory
@Override
public Thread newThread(Runnable r)
{
return new Thread(r, threadName);
return new Thread(r, threadName);
}
}
+26 -51
View File
@@ -18,17 +18,12 @@
package com.seibel.lod.util;
import java.awt.Color;
import java.io.File;
import java.util.HashSet;
import com.seibel.lod.builders.bufferBuilding.lodTemplates.Box;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.VanillaOverdraw;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.wrappers.MinecraftWrapper;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher.CompiledChunk;
@@ -46,9 +41,12 @@ import net.minecraft.world.gen.Heightmap;
import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld;
import java.awt.*;
import java.io.File;
import java.util.HashSet;
/**
* This class holds methods and constants that may be used in multiple places.
*
* @author James Seibel
* @version 10-11-2021
*/
@@ -58,7 +56,7 @@ public class LodUtil
/**
* vanilla render distances less than or equal to this will not allow partial
* overdraw. The VanillaOverdraw with either be ALWAYS or NEVER.
* overdraw. The VanillaOverdraw with either be ALWAYS or NEVER.
*/
public static final int MINIMUM_RENDER_DISTANCE_FOR_PARTIAL_OVERDRAW = 5;
@@ -82,29 +80,22 @@ public class LodUtil
public static final Color[] DEBUG_DETAIL_LEVEL_COLORS = new Color[] { Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.WHITE, Color.GRAY, Color.BLACK };
/**
* 512 blocks wide
*/
public static final byte REGION_DETAIL_LEVEL = 9;
/**
* 16 blocks wide
*/
public static final byte CHUNK_DETAIL_LEVEL = 4;
/**
* 1 block wide
*/
public static final byte BLOCK_DETAIL_LEVEL = 0;
public static final byte DETAIL_OPTIONS = 10;
/** 512 blocks wide */
public static final byte REGION_DETAIL_LEVEL = DETAIL_OPTIONS - 1;
/** 16 blocks wide */
public static final byte CHUNK_DETAIL_LEVEL = 4;
/** 1 block wide */
public static final byte BLOCK_DETAIL_LEVEL = 0;
public static final short MAX_VERTICAL_DATA = 4;
/**
* measured in Blocks <br>
* detail level 9
* detail level max - 1
*/
public static final short REGION_WIDTH = 512;
public static final short REGION_WIDTH = 1 << REGION_DETAIL_LEVEL;
/**
* measured in Blocks <br>
* detail level 4
@@ -117,10 +108,8 @@ public class LodUtil
public static final short BLOCK_WIDTH = 1;
/**
* number of chunks wide
*/
public static final int REGION_WIDTH_IN_CHUNKS = 32;
/** number of chunks wide */
public static final int REGION_WIDTH_IN_CHUNKS = REGION_WIDTH / CHUNK_WIDTH;
/**
@@ -156,7 +145,6 @@ public class LodUtil
/**
* Gets the first valid ServerWorld.
*
* @return null if there are no ServerWorlds
*/
public static ServerWorld getFirstValidServerWorld()
@@ -174,7 +162,6 @@ public class LodUtil
/**
* Gets the ServerWorld for the relevant dimension.
*
* @return null if there is no ServerWorld for the given dimension
*/
public static ServerWorld getServerWorldFromDimension(DimensionType dimension)
@@ -198,9 +185,7 @@ public class LodUtil
return returnWorld;
}
/**
* Convert a 2D absolute position into a quad tree relative position.
*/
/** Convert a 2D absolute position into a quad tree relative position. */
public static RegionPos convertGenericPosToRegionPos(int x, int z, int detailLevel)
{
int relativePosX = Math.floorDiv(x, (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel));
@@ -209,9 +194,7 @@ public class LodUtil
return new RegionPos(relativePosX, relativePosZ);
}
/**
* Convert a 2D absolute position into a quad tree relative position.
*/
/** Convert a 2D absolute position into a quad tree relative position. */
public static int convertLevelPos(int pos, int currentDetailLevel, int targetDetailLevel)
{
return Math.floorDiv(pos, (int) Math.pow(2, targetDetailLevel - currentDetailLevel));
@@ -293,9 +276,7 @@ public class LodUtil
}
}
/**
* returns the server name, IP and game version.
*/
/** returns the server name, IP and game version. */
public static String getServerId()
{
ServerData server = mc.getCurrentServer();
@@ -308,9 +289,7 @@ public class LodUtil
}
/**
* Convert a BlockColors int into a Color object.
*/
/** Convert a BlockColors int into a Color object */
public static Color intToColor(int num)
{
int filter = 0b11111111;
@@ -322,9 +301,7 @@ public class LodUtil
return new Color(red, green, blue);
}
/**
* Convert a Color into a BlockColors object.
*/
/** Convert a Color into a BlockColors object. */
public static int colorToInt(Color color)
{
return color.getRGB();
@@ -371,7 +348,7 @@ public class LodUtil
VanillaOverdraw overdraw = LodConfig.CLIENT.graphics.vanillaOverdraw.get();
// apply distance based rules for dynamic
if (overdraw == VanillaOverdraw.DYNAMIC
if (overdraw == VanillaOverdraw.DYNAMIC
&& chunkRenderDist <= MINIMUM_RENDER_DISTANCE_FOR_PARTIAL_OVERDRAW)
{
// The vanilla render distance isn't far enough
@@ -398,14 +375,14 @@ public class LodUtil
{
case ALWAYS:
// don't skip any positions
return new HashSet<ChunkPos>();
return new HashSet<>();
case DYNAMIC:
// only skip positions that are greater than
// 4/5ths the render distance
skipRadius = (int) Math.ceil(chunkRenderDist * (4.0 / 5.0));
break;
default:
case NEVER:
// skip chunks in render distance that are rendered
@@ -428,11 +405,9 @@ public class LodUtil
for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++)
{
if (x <= centerChunk.x - skipRadius || x >= centerChunk.x + skipRadius
||
z <= centerChunk.z - skipRadius || z >= centerChunk.z + skipRadius)
|| z <= centerChunk.z - skipRadius || z >= centerChunk.z + skipRadius)
{
posToSkip.remove(new ChunkPos(x, z));
continue;
}
}
}
@@ -9,11 +9,12 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static com.seibel.lod.util.LodUtil.DETAIL_OPTIONS;
/**
* Holds data used by specific threads so
* Holds data used by specific threads so
* the data doesn't have to be recreated every
* time it is needed.
*
* @author Leonardo Amato
* @version 9-25-2021
*/
@@ -95,35 +96,6 @@ public class ThreadMapUtil
/** returns the array NOT cleared every time */
public static long[] getSingleUpdateArray()
{
if (!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null))
{
threadSingleUpdateMap.put(Thread.currentThread().getName(), new long[4]);
}
return threadSingleUpdateMap.get(Thread.currentThread().getName());
}
/** returns the array NOT cleared every time */
public static long[] getBuilderArray(int detailLevel)
{
if (!threadBuilderArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderArrayMap.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[5][];
int size = 1;
for (int i = 0; i < 5; i++)
{
array[i] = new long[size * size];
size = size << 1;
}
threadBuilderArrayMap.put(Thread.currentThread().getName(), array);
}
return threadBuilderArrayMap.get(Thread.currentThread().getName())[detailLevel];
}
/** returns the array filled with 0's */
public static long[] getBuilderVerticalArray(int detailLevel)
{
@@ -193,8 +165,8 @@ public class ThreadMapUtil
{
if (!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null))
{
long[][] array = new long[10][];
for (int i = 1; i < 10; i++)
long[][] array = new long[DETAIL_OPTIONS][];
for (int i = 1; i < DETAIL_OPTIONS; i++)
array[i] = new long[DetailDistanceUtil.getMaxVerticalData(i - 1) * 4];
verticalUpdate.put(Thread.currentThread().getName(), array);
}
@@ -1,10 +1,6 @@
package com.seibel.lod.wrappers;
import java.awt.Color;
import java.io.File;
import com.seibel.lod.util.LodUtil;
import net.minecraft.client.GameSettings;
import net.minecraft.client.MainWindow;
import net.minecraft.client.Minecraft;
@@ -23,10 +19,12 @@ import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.Direction;
import net.minecraft.world.DimensionType;
import java.awt.*;
import java.io.File;
/**
* A singleton that wraps the Minecraft class
* to allow for easier movement between Minecraft versions.
*
* @author James Seibel
* @version 9-16-2021
*/
@@ -36,8 +34,10 @@ public class MinecraftWrapper
private final Minecraft mc = Minecraft.getInstance();
/** The lightmap for the current:
* Time, dimension, brightness setting, etc. */
/**
* The lightmap for the current:
* Time, dimension, brightness setting, etc.
*/
private NativeImage lightMap = null;
private MinecraftWrapper()
@@ -54,9 +54,9 @@ public class MinecraftWrapper
/**
* This should be called at the beginning of every frame to
* clear any Minecraft data that becomes out of date after a frame. <br> <br>
*
* <p>
* LightMaps and other time sensitive objects fall in this category. <br> <br>
*
* <p>
* This doesn't affect OpenGL objects in any way.
*/
public void clearFrameObjectCache()
@@ -90,7 +90,7 @@ public class MinecraftWrapper
return LodUtil.getDimensionIDFromWorld(mc.level);
}
/**
/**
* This texture changes every frame
*/
public NativeImage getCurrentLightMap()
@@ -101,7 +101,7 @@ public class MinecraftWrapper
LightTexture tex = mc.gameRenderer.lightTexture();
lightMap = tex.lightPixels;
}
// // hotswap this to true, then back to false to write a file
// // (and not write a file every frame)
// if (false)
@@ -123,7 +123,6 @@ public class MinecraftWrapper
/**
* Returns the color int at the given pixel coordinates
* from the current lightmap.
*
* @param u x location in texture space
* @param v z location in texture space
*/
@@ -141,7 +140,6 @@ public class MinecraftWrapper
/**
* Returns the Color at the given pixel coordinates
* from the current lightmap.
*
* @param u x location in texture space
* @param v z location in texture space
*/
@@ -166,7 +164,7 @@ public class MinecraftWrapper
{
return mc.options;
}
public ModelManager getModelManager()
{
return mc.getModelManager();
@@ -174,9 +172,9 @@ public class MinecraftWrapper
public ClientWorld getClientWorld()
{
return mc.level;
return mc.level;
}
/** Measured in chunks */
public int getRenderDistance()
{