Removed level pos and data arrays

This commit is contained in:
Leonardo
2021-09-07 17:23:22 +02:00
parent 53a66268cb
commit f76fa17e25
20 changed files with 660 additions and 1421 deletions
@@ -1,28 +0,0 @@
package com.seibel.lod.builders;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.util.LodUtil;
import net.minecraft.util.math.ChunkPos;
/**
* @author Leonardo Amato
* @version 22-08-2021
*/
public class GenerationRequest
{
public final LevelPos levelPos;
public final DistanceGenerationMode generationMode;
public GenerationRequest(LevelPos levelPos, DistanceGenerationMode generationMode)
{
this.levelPos = levelPos;
this.generationMode = generationMode;
}
public ChunkPos getChunkPos()
{
LevelPos chunkLevelPos = levelPos.getConvertedLevelPos(LodUtil.CHUNK_DETAIL_LEVEL);
return new ChunkPos(chunkLevelPos.posX, chunkLevelPos.posZ);
}
}
@@ -20,20 +20,15 @@ package com.seibel.lod.builders;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.seibel.lod.objects.*;
import org.lwjgl.opengl.GL11;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.render.LodRenderer;
import com.seibel.lod.util.LodThreadFactory;
@@ -49,7 +44,7 @@ import net.minecraft.util.math.ChunkPos;
* This object is used to create NearFarBuffer objects.
*
* @author James Seibel
* @version 9-6-2021
* @version 8-24-2021
*/
public class LodBufferBuilder
{
@@ -105,15 +100,18 @@ public class LodBufferBuilder
*/
private ReentrantLock bufferLock = new ReentrantLock();
private static final int NUMBER_OF_DIRECTION = 4;
//in order -x, +x, -z, +z
private static final int[][] ADJ_DIRECTION = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private volatile Object[][] setsToRender;
private volatile RegionPos center;
/** This is the ChunkPos the player was at the last time the buffers were built.
* IE the center of the buffers last time they were built */
private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0,0);
private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0,0);
public LodBufferBuilder()
{
@@ -148,6 +146,8 @@ public class LodBufferBuilder
ChunkPos playerChunkPos = new ChunkPos(playerBlockPos);
BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition();
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
Thread thread = new Thread(() ->
{
@@ -165,8 +165,11 @@ public class LodBufferBuilder
ArrayList<Callable<Boolean>> nodeToRenderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length);
startBuffers(fullRegen, lodDim);
// =====================//
// RENDERING PART //
// =====================//
RegionPos playerRegionPos = new RegionPos(playerChunkPos);
if (center == null)
center = playerRegionPos;
@@ -176,16 +179,8 @@ public class LodBufferBuilder
if (setsToRender.length != lodDim.regions.length)
setsToRender = new Object[lodDim.regions.length][lodDim.regions.length];
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterX(), playerRegionPos.z - lodDim.getCenterZ());
if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0)
{
move(worldRegionOffset, Math.floorDiv(lodDim.getWidth(), 2));
}
for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++)
{
@@ -199,117 +194,98 @@ public class LodBufferBuilder
// local position in the vbo and bufferBuilder arrays
BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion];
LodRegion region = lodDim.getRegion(regionPos.x, regionPos.z);
if (region == null) continue;
byte minDetail = region.getMinDetailLevel();
// make sure the buffers weren't
// changed while we were running this method
if (currentBuffer == null || (currentBuffer != null && !currentBuffer.building()))
return;
//previous setToRender chache
if (setsToRender[xRegion][zRegion] == null)
{
setsToRender[xRegion][zRegion] = new ConcurrentHashMap<LevelPos, MutableBoolean>();
}
ConcurrentMap<LevelPos, MutableBoolean> nodeToRender = (ConcurrentMap<LevelPos, MutableBoolean>) setsToRender[xRegion][zRegion];
final int xR = xRegion;
final int zR = zRegion;
Callable<Boolean> dataToRenderThread = () ->
{
//previous setToRender chache
if (setsToRender[xR][zR] == null)
{
setsToRender[xR][zR] = new PosToRenderContainer(minDetail, regionPos.x, regionPos.z);
}
PosToRenderContainer posToRender = (PosToRenderContainer) setsToRender[xR][zR];
posToRender.clear(minDetail, regionPos.x, regionPos.z);
lodDim.getDataToRender(
nodeToRender,
posToRender,
regionPos,
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
byte detailLevel;
int posX;
int posZ;
byte detailLevel;
int xAdj;
int zAdj;
int chunkXdist;
int chunkZdist;
short gameChunkRenderDistance = (short) (renderer.vanillaRenderedChunks.length/2 - 1);
for (LevelPos posToRender : nodeToRender.keySet())
short gameChunkRenderDistance = (short) (renderer.vanillaRenderedChunks.length / 2 - 1);
long lodData;
long[] adjData;
for (int index = 0; index < posToRender.getNumberOfPos(); index++)
{
if (!nodeToRender.get(posToRender).booleanValue())
detailLevel = posToRender.getNthDetailLevel(index);
posX = posToRender.getNthPosX(index);
posZ = posToRender.getNthPosZ(index);
// skip any chunks that Minecraft is going to render
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist)
&& gameChunkRenderDistance >= Math.abs(chunkZdist)
&& detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL
&& renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
{
nodeToRender.remove(posToRender);
continue;
}
nodeToRender.get(posToRender).setFalse();
// skip any chunks that Minecraft is going to render
chunkXdist = posToRender.getChunkPosX() - playerChunkPos.x;
chunkZdist = posToRender.getChunkPosZ() - playerChunkPos.z;
if(gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist) && posToRender.detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL)
{
if (renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])
{
continue;
}
}
posX = posToRender.posX;
posZ = posToRender.posZ;
detailLevel = posToRender.detailLevel;
// skip any chunks that Minecraft is going to render
try
{
boolean disableFix = false;
if (lodDim.doesDataExist(posToRender.clone()))
if (lodDim.doesDataExist(detailLevel, posX, posZ))
{
short[] lodData = lodDim.getData(posToRender);
short[][][] adjData = new short[2][2][];
/**TODO The following two for are too complex*/
for (int x : new int[]{0, 1})
lodData = lodDim.getData(detailLevel, posX, posZ);
adjData = new long[NUMBER_OF_DIRECTION];
for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++)
{
posToRender.changeParameters(detailLevel, posX + x * 2 - 1, posZ);
chunkXdist = posToRender.getChunkPosX() - playerChunkPos.x;
chunkZdist = posToRender.getChunkPosZ() - playerChunkPos.z;
if(gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
xAdj = posX + ADJ_DIRECTION[direction][0];
zAdj = posZ + ADJ_DIRECTION[direction][1];
chunkXdist = LevelPosUtil.getChunkPos(detailLevel,xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel,xAdj) - playerChunkPos.z;
if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
{
if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]
&& (nodeToRender.containsKey(posToRender) || disableFix))
&& (posToRender.contains(detailLevel, xAdj, zAdj) || disableFix))
{
adjData[0][x] = lodDim.getData(posToRender);
adjData[direction]= lodDim.getData(detailLevel, xAdj, zAdj);
}
}else{
if (nodeToRender.containsKey(posToRender) || disableFix)
{
adjData[0][x] = lodDim.getData(posToRender);
}
}
}
for (int z : new int[]{0, 1})
{
posToRender.changeParameters(detailLevel, posX, posZ + z * 2 - 1);
chunkXdist = posToRender.getChunkPosX() - playerChunkPos.x;
chunkZdist = posToRender.getChunkPosZ() - playerChunkPos.z;
if(gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist))
} else
{
if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance+ 1]
&& (nodeToRender.containsKey(posToRender) || disableFix))
if (posToRender.contains(detailLevel, xAdj, zAdj) || disableFix)
{
adjData[1][z] = lodDim.getData(posToRender);
}
}else{
if (nodeToRender.containsKey(posToRender) || disableFix)
{
adjData[1][z] = lodDim.getData(posToRender);
adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj);
}
}
}
posToRender.changeParameters(detailLevel, posX, posZ);
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, lodData, adjData,
posToRender, renderer.previousDebugMode);
LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPos, lodData, adjData,
detailLevel, posX, posZ, renderer.previousDebugMode);
}
} catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
return false;
}
}// for pos to in list to render
// the thread executed successfully
return true;
};
@@ -344,7 +320,7 @@ public class LodBufferBuilder
// ClientProxy.LOGGER.info("Buffer Build time: " + buildTime + " ms" + '\n' +
// "Tree cutting time: " + treeTime + " ms" + '\n' +
// "Rendering time: " + renderingTime + " ms");
// mark that the buildable buffers as ready to swap
switchVbos = true;
} catch (Exception e)
@@ -367,110 +343,12 @@ public class LodBufferBuilder
}
});
mainGenThread.execute(thread);
return;
}
/**
* Move the center of this LodDimension and move all owned
* regions over by the given x and z offset. <br><br>
* <p>
* Synchronized to prevent multiple moves happening on top of each other.
*/
public void move(RegionPos regionOffset, int width)
{
int xOffset = regionOffset.x;
int zOffset = regionOffset.z;
// if the x or z offset is equal to or greater than
// the total size, just delete the current data
// and update the centerX and/or centerZ
if (Math.abs(xOffset) >= width || Math.abs(zOffset) >= width)
{
for (int x = 0; x < width; x++)
{
for (int z = 0; z < width; z++)
{
setsToRender[x][z] = null;
}
}
// update the new center
center.x += xOffset;
center.z += zOffset;
return;
}
// X
if (xOffset > 0)
{
// move everything over to the left (as the center moves to the right)
for (int x = 0; x < width; x++)
{
for (int z = 0; z < width; z++)
{
if (x + xOffset < width)
setsToRender[x][z] = setsToRender[x + xOffset][z];
else
setsToRender[x][z] = null;
}
}
} else
{
// move everything over to the right (as the center moves to the left)
for (int x = width - 1; x >= 0; x--)
{
for (int z = 0; z < width; z++)
{
if (x + xOffset >= 0)
setsToRender[x][z] = setsToRender[x + xOffset][z];
else
setsToRender[x][z] = null;
}
}
}
// Z
if (zOffset > 0)
{
// move everything up (as the center moves down)
for (int x = 0; x < width; x++)
{
for (int z = 0; z < width; z++)
{
if (z + zOffset < width)
setsToRender[x][z] = setsToRender[x][z + zOffset];
else
setsToRender[x][z] = null;
}
}
} else
{
// move everything down (as the center moves up)
for (int x = 0; x < width; x++)
{
for (int z = width - 1; z >= 0; z--)
{
if (z + zOffset >= 0)
setsToRender[x][z] = setsToRender[x][z + zOffset];
else
setsToRender[x][z] = null;
}
}
}
// update the new center
center.x += xOffset;
center.z += zOffset;
}
//===============================//
// BufferBuilder related methods //
//===============================//
@@ -573,7 +451,6 @@ public class LodBufferBuilder
}
}
/**
* Get the newly created VBOs
*/
@@ -586,9 +463,9 @@ public class LodBufferBuilder
VertexBuffer[][] tmp = drawableVbos;
drawableVbos = buildableVbos;
buildableVbos = tmp;
drawableCenterChunkPos = buildableCenterChunkPos;
// the vbos have been swapped
switchVbos = false;
bufferLock.unlock();
@@ -603,7 +480,7 @@ public class LodBufferBuilder
{
public VertexBuffer[][] vbos;
public ChunkPos drawableCenterChunkPos;
public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos)
{
vbos = newVbos;
@@ -20,19 +20,18 @@ package com.seibel.lod.builders;
import java.awt.Color;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodDetail;
import com.seibel.lod.objects.DataPoint;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodWorld;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.objects.*;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrapper.MinecraftWrapper;
import com.seibel.lod.wrapper.MinecraftWrapper;
import com.sun.org.apache.xpath.internal.operations.Bool;
import net.minecraft.block.AbstractPlantBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
@@ -41,6 +40,7 @@ import net.minecraft.block.GrassBlock;
import net.minecraft.block.IGrowable;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.client.Minecraft;
import net.minecraft.world.DimensionType;
import net.minecraft.world.IWorld;
import net.minecraft.world.biome.Biome;
@@ -131,7 +131,6 @@ public class LodBuilder
generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode));
} catch (IllegalArgumentException | NullPointerException e)
{
System.out.println("Chunk pos " + chunk.getPos());
e.printStackTrace();
// if the world changes while LODs are being generated
// they will throw errors as they try to access things that no longer
@@ -161,7 +160,6 @@ public class LodBuilder
public void generateLodNodeFromChunk(LodDimension lodDim, IChunk chunk, LodBuilderConfig config)
throws IllegalArgumentException
{
if (chunk == null)
throw new IllegalArgumentException("generateLodFromChunk given a null chunk");
@@ -169,17 +167,22 @@ public class LodBuilder
int startZ;
int endX;
int endZ;
short[] color;
int color;
short height;
short depth;
short[] data;
LevelPos levelPos = new LevelPos((byte) 0, 0, 0);
levelPos.changeParameters(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
levelPos.convert(LodUtil.REGION_DETAIL_LEVEL);
long data;
try
{
byte minDetailLevel = lodDim.getRegion(levelPos).getMinDetailLevel();
LodDetail detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel);
LodDetail detail;
LodRegion region = lodDim.getRegion(chunk.getPos().getRegionX(), chunk.getPos().getRegionZ());
if (region == null)
return;
byte minDetailLevel = region.getMinDetailLevel();
detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel);
byte detailLevel = detail.detailLevel;
int posX;
int posZ;
for (int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++)
{
startX = detail.startX[i];
@@ -199,23 +202,23 @@ public class LodBuilder
startZ, endX, endZ);
depth = 0;
}
levelPos.changeParameters((byte) 0,
chunk.getPos().x * 16 + startX,
chunk.getPos().z * 16 + startZ);
levelPos.convert(detail.detailLevel);
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel);
boolean isServer = config.distanceGenerationMode == DistanceGenerationMode.SERVER;
data = DataPoint.createDataPoint(height, depth, color[0], color[1], color[2]);
lodDim.addData(levelPos,
data = DataPoint.createDataPoint(height, depth, ColorUtil.getRed(color), ColorUtil.getGreen(color), ColorUtil.getBlue(color));
lodDim.addData(detailLevel,
posX,
posZ,
data,
false,
isServer);
}
levelPos.changeParameters(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
lodDim.updateData(levelPos);
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
} catch (Exception e)
{
//e.printStackTrace();
e.printStackTrace();
}
}
@@ -352,8 +355,8 @@ public class LodBuilder
* otherwise only use the block's
* material color
*/
private short[] generateLodColorForArea(IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX,
int endZ)
private int generateLodColorForArea(IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX,
int endZ)
{
ChunkSection[] chunkSections = chunk.getSections();
@@ -427,8 +430,7 @@ public class LodBuilder
red /= numbOfBlocks;
green /= numbOfBlocks;
blue /= numbOfBlocks;
return new short[]{(short) red, (short) green, (short) blue};
return ColorUtil.rgbToInt(red,green,blue);
}
/**
@@ -18,7 +18,6 @@
package com.seibel.lod.builders.lodTemplates;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.objects.LevelPos.LevelPos;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.math.BlockPos;
@@ -32,8 +31,8 @@ import net.minecraft.util.math.BlockPos;
*/
public abstract class AbstractLodTemplate
{
public abstract void addLodToBuffer(BufferBuilder buffer, BlockPos playerBlockPos, short[] data, short[][][] adjData,
LevelPos levelPos, DebugMode debugging);
public abstract void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
byte detailLevel, int posX, int posZ,DebugMode debugging);
/**
* add the given position and color to the buffer
@@ -21,7 +21,7 @@ import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.enums.ShadingMode;
import com.seibel.lod.objects.DataPoint;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.objects.LevelPosUtil;
import com.seibel.lod.util.ColorUtil;
import com.seibel.lod.util.LodUtil;
@@ -35,71 +35,63 @@ import net.minecraft.util.math.BlockPos;
* Builds LODs as rectangular prisms.
*
* @author James Seibel
* @version 9-6-2021
* @version 8-10-2021
*/
public class CubicLodTemplate extends AbstractLodTemplate
{
private final int CULL_OFFSET = 16;
public CubicLodTemplate()
{
}
@Override
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, short[] data, short[][][] adjData,
LevelPos levelPos, DebugMode debugging)
public void addLodToBuffer(BufferBuilder buffer, BlockPos playerBlockPos, long data, long[] adjData,
byte detailLevel, int posX, int posZ,DebugMode debugging)
{
AxisAlignedBB bbox;
int width = 1 << levelPos.detailLevel;
int width = 1 << detailLevel;
// add each LOD for the detail level
bbox = generateBoundingBox(
DataPoint.getHeight(data),
DataPoint.getDepth(data),
width,
levelPos.posX * width,
posX * width,
0,
levelPos.posZ * width,
bufferCenterBlockPos);
posZ * width);
int color = DataPoint.getColor(data);
if (debugging != DebugMode.OFF)
{
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[levelPos.detailLevel].getRGB();
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel].getRGB();
}
if (bbox != null)
{
addBoundingBoxToBuffer(buffer, bbox, color, bufferCenterBlockPos, adjData);
addBoundingBoxToBuffer(buffer, bbox, color, playerBlockPos, adjData);
}
}
private AxisAlignedBB generateBoundingBox(int height, int depth, int width, double xOffset, double yOffset, double zOffset, BlockPos bufferCenterBlockPos)
private AxisAlignedBB generateBoundingBox(int height, int depth, int width, double xOffset, double yOffset, double zOffset)
{
// don't add an LOD if it is empty
if (height == -1 && depth == -1)
return null;
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 it's x/z position in the world since
// it uses doubles to specify its location, unlike the model view matrix
// which only uses floats
double x = -bufferCenterBlockPos.getX();
double z = -bufferCenterBlockPos.getZ();
return new AxisAlignedBB(0, depth, 0, width, height, width).move(xOffset, yOffset, zOffset).move(x, 0, z);
return new AxisAlignedBB(0, depth, 0, width, height, width).move(xOffset, yOffset, zOffset);
}
private void addBoundingBoxToBuffer(BufferBuilder buffer, AxisAlignedBB bb, int c, BlockPos playerBlockPos, short[][][] adjData)
private void addBoundingBoxToBuffer(BufferBuilder buffer, AxisAlignedBB bb, int c, BlockPos playerBlockPos, long[] adjData)
{
int topColor = c;
int bottomColor = c;
@@ -107,7 +99,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
int southColor = c;
int westColor = c;
int eastColor = c;
// darken the bottom and side colors if requested
if (LodConfig.CLIENT.graphics.shadingMode.get() == ShadingMode.DARKEN_SIDES)
{
@@ -123,11 +115,11 @@ public class CubicLodTemplate extends AbstractLodTemplate
westColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.WEST, true));
eastColor = ColorUtil.applyShade(c, mc.level.getShade(Direction.EAST, true));
}
// apply the user specified saturation and brightness
float saturationMultiplier = LodConfig.CLIENT.graphics.saturationMultiplier.get().floatValue();
float brightnessMultiplier = LodConfig.CLIENT.graphics.brightnessMultiplier.get().floatValue();
if (saturationMultiplier != 1 || brightnessMultiplier != 1)
{
topColor = ColorUtil.applySaturationAndBrightnessMultipliers(topColor, saturationMultiplier, brightnessMultiplier);
@@ -139,8 +131,8 @@ public class CubicLodTemplate extends AbstractLodTemplate
}
int minY;
int maxY;
short[] data;
long data;
int red;
int green;
int blue;
@@ -171,83 +163,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
}
if (playerBlockPos.getZ() > bb.minZ - CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(northColor);
green = ColorUtil.getGreen(northColor);
blue = ColorUtil.getBlue(northColor);
alpha = ColorUtil.getAlpha(northColor);
// south (facing -Z)
data = adjData[1][1];
if (data == null)
{
addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
}
else
{
maxY = DataPoint.getHeight(data);
if (maxY < bb.maxY)
{
minY = (int) Math.max(maxY, bb.minY);
addPosAndColor(buffer, bb.maxX, minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, minY, bb.maxZ, red, green, blue, alpha);
}
minY = DataPoint.getDepth(data);
if (minY > bb.minY)
{
maxY = (int) Math.min(minY, bb.maxY);
addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
}
}
}
if (playerBlockPos.getZ() < bb.maxZ + CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(southColor);
green = ColorUtil.getGreen(southColor);
blue = ColorUtil.getBlue(southColor);
alpha = ColorUtil.getAlpha(southColor);
data = adjData[1][0];
// north (facing +Z)
if (data == null)
{
addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
else
{
maxY = DataPoint.getHeight(data);
if (maxY < bb.maxY)
{
minY = (int) Math.max(maxY, bb.minY);
addPosAndColor(buffer, bb.minX, minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, minY, bb.minZ, red, green, blue, alpha);
}
minY = DataPoint.getDepth(data);
if (minY > bb.minY)
{
maxY = (int) Math.min(minY, bb.maxY);
addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
}
}
if (playerBlockPos.getX() < bb.maxX + CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(westColor);
@@ -255,8 +171,8 @@ public class CubicLodTemplate extends AbstractLodTemplate
blue = ColorUtil.getBlue(westColor);
alpha = ColorUtil.getAlpha(westColor);
// west (facing -X)
data = adjData[0][0];
if (data == null)
data = adjData[0];
if (data == 0)
{
addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
@@ -285,7 +201,7 @@ public class CubicLodTemplate extends AbstractLodTemplate
}
}
}
if (playerBlockPos.getX() > bb.minX - CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(eastColor);
@@ -293,8 +209,8 @@ public class CubicLodTemplate extends AbstractLodTemplate
blue = ColorUtil.getBlue(eastColor);
alpha = ColorUtil.getAlpha(eastColor);
// east (facing +X)
data = adjData[0][1];
if (data == null)
data = adjData[1];
if (data == 0)
{
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
@@ -323,13 +239,89 @@ public class CubicLodTemplate extends AbstractLodTemplate
}
}
}
if (playerBlockPos.getZ() > bb.minZ - CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(northColor);
green = ColorUtil.getGreen(northColor);
blue = ColorUtil.getBlue(northColor);
alpha = ColorUtil.getAlpha(northColor);
data = adjData[3];
// north (facing +Z)
if (data == 0)
{
addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
}
else
{
maxY = DataPoint.getHeight(data);
if (maxY < bb.maxY)
{
minY = (int) Math.max(maxY, bb.minY);
addPosAndColor(buffer, bb.maxX, minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, minY, bb.maxZ, red, green, blue, alpha);
}
minY = DataPoint.getDepth(data);
if (minY > bb.minY)
{
maxY = (int) Math.min(minY, bb.maxY);
addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, maxY, bb.maxZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, red, green, blue, alpha);
}
}
}
if (playerBlockPos.getZ() < bb.maxZ + CULL_OFFSET || disableCulling)
{
red = ColorUtil.getRed(southColor);
green = ColorUtil.getGreen(southColor);
blue = ColorUtil.getBlue(southColor);
alpha = ColorUtil.getAlpha(southColor);
data = adjData[2];
// south (facing -Z)
if (data == 0)
{
addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
else
{
maxY = DataPoint.getHeight(data);
if (maxY < bb.maxY)
{
minY = (int) Math.max(maxY, bb.minY);
addPosAndColor(buffer, bb.minX, minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, minY, bb.minZ, red, green, blue, alpha);
}
minY = DataPoint.getDepth(data);
if (minY > bb.minY)
{
maxY = (int) Math.min(minY, bb.maxY);
addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.minX, maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, maxY, bb.minZ, red, green, blue, alpha);
addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, red, green, blue, alpha);
}
}
}
}
@Override
public int getBufferMemoryForSingleNode()
{
// (sidesOnACube * pointsInASquare * (positionPoints + colorPoints)))
return (6 * 4 * (3 + 4));
}
}
@@ -18,7 +18,6 @@
package com.seibel.lod.builders.lodTemplates;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.objects.LevelPos.LevelPos;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.math.BlockPos;
@@ -35,8 +34,8 @@ import net.minecraft.util.math.BlockPos;
public class DynamicLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(BufferBuilder buffer, BlockPos playerBlockPos, short[] data, short[][][] adjData,
LevelPos levelPos, DebugMode debugging)
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
byte detailLevel, int posX, int posZ,DebugMode debugging)
{
System.err.println("DynamicLodTemplate not implemented!");
}
@@ -18,7 +18,6 @@
package com.seibel.lod.builders.lodTemplates;
import com.seibel.lod.enums.DebugMode;
import com.seibel.lod.objects.LevelPos.LevelPos;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.math.BlockPos;
@@ -33,8 +32,8 @@ import net.minecraft.util.math.BlockPos;
public class TriangularLodTemplate extends AbstractLodTemplate
{
@Override
public void addLodToBuffer(BufferBuilder buffer, BlockPos playerBlockPos, short[] data, short[][][] adjData,
LevelPos levelPos, DebugMode debugging)
public void addLodToBuffer(BufferBuilder buffer, BlockPos bufferCenterBlockPos, long data, long[] adjData,
byte detailLevel, int posX, int posZ,DebugMode debugging)
{
System.err.println("DynamicLodTemplate not implemented!");
}
@@ -1,33 +1,24 @@
package com.seibel.lod.builders.worldGeneration;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.seibel.lod.objects.LevelPosUtil;
import com.seibel.lod.objects.PosToGenerateContainer;
import com.seibel.lod.builders.GenerationRequest;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.render.LodRenderer;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrapper.MinecraftWrapper;
import net.minecraft.util.math.BlockPos;
import com.seibel.lod.wrapper.MinecraftWrapper;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.WorldWorkerManager;
@@ -75,10 +66,6 @@ public class LodWorldGenerator
*/
public static final LodWorldGenerator INSTANCE = new LodWorldGenerator();
public volatile ConcurrentMap<LevelPos, MutableBoolean> nodeToGenerate;
SortedSet<LevelPos> nodeToGenerateListNear;
SortedSet<LevelPos> nodeToGenerateListFar;
private LodWorldGenerator()
{
@@ -108,14 +95,9 @@ public class LodWorldGenerator
try
{
// round the player's block position down to the nearest chunk BlockPos
ChunkPos playerChunkPos = new ChunkPos(mc.getPlayer().blockPosition());
BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition();
int playerPosX = mc.getPlayer().blockPosition().getX();
int playerPosZ = mc.getPlayer().blockPosition().getZ();
// used when determining which chunks are closer when queuing distance
// generation
int minChunkDist = Integer.MAX_VALUE;
ArrayList<GenerationRequest> chunksToGen = new ArrayList<>(maxChunkGenRequests);
// if we don't have a full number of chunks to generate in chunksToGen
// we can top it off from this reserve
@@ -123,92 +105,34 @@ public class LodWorldGenerator
//=======================================//
// create the generation Request objects //
//=======================================//
List<GenerationRequest> generationRequestList = new ArrayList<>(maxChunkGenRequests);
if (nodeToGenerate == null)
nodeToGenerate = new ConcurrentHashMap<>();
Comparator<LevelPos> posNearComparator = LevelPos.getPosComparator(
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
Comparator<LevelPos> posFarComparator = LevelPos.getPosAndDetailComparator(
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
nodeToGenerateListNear = new TreeSet(posNearComparator);
nodeToGenerateListFar = new TreeSet(posFarComparator);
lodDim.getDataToGenerate(
nodeToGenerate,
playerBlockPosRounded.getX(),
playerBlockPosRounded.getZ());
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension);
byte farDetail = (byte) 8;
PosToGenerateContainer posToGenerate = lodDim.getDataToGenerate(
farDetail,
maxChunkGenRequests,
0.25,
playerPosX,
playerPosZ);
//System.out.println(posToGenerate);
//here we prepare two sorted set
//the first contains the near pos to render
//the second contain the far pos to render
byte farDetail = (byte) 7;
for (LevelPos pos : nodeToGenerate.keySet())
byte detailLevel;
int posX;
int posZ;
int[] levelPos;
for (int index = 0; index < posToGenerate.getNumberOfPos(); index++)
{
if (!nodeToGenerate.get(pos).booleanValue())
{
nodeToGenerate.remove(pos);
} else
{
if (pos.detailLevel > farDetail){
nodeToGenerateListFar.add(pos);
}
nodeToGenerateListNear.add(pos);
nodeToGenerate.get(pos).setFalse();
}
}
levelPos = posToGenerate.getNthPos(index);
if(levelPos[0] == 0)
continue;
detailLevel = (byte) (levelPos[0] -1);
posX = levelPos[1];
posZ = levelPos[2];
int maxDistance;
byte circle;
LevelPos levelPos;
int requesting = maxChunkGenRequests;
int requestingFar = maxChunkGenRequests / 4;
while (requesting > 0 && !nodeToGenerateListNear.isEmpty())
{
levelPos = nodeToGenerateListNear.first();
//.out.println(levelPos);
nodeToGenerate.remove(levelPos);
nodeToGenerateListNear.remove(levelPos);
nodeToGenerateListFar.remove(levelPos);
//maxDistance = levelPos.maxDistance(
// playerBlockPosRounded.getX(),
// playerBlockPosRounded.getZ());
//circle = DetailDistanceUtil.getDistanceGenerationInverse(maxDistance);
generationRequestList.add(new GenerationRequest(levelPos, DetailDistanceUtil.getDistanceGenerationMode(levelPos.detailLevel)));
requesting--;
if (requestingFar > 0 && !nodeToGenerateListFar.isEmpty())
{
levelPos = nodeToGenerateListFar.first();
nodeToGenerate.remove(levelPos);
nodeToGenerateListNear.remove(levelPos);
nodeToGenerateListFar.remove(levelPos);
if (levelPos.detailLevel >= farDetail)
{
//maxDistance = levelPos.maxDistance( playerBlockPosRounded.getX(), playerBlockPosRounded.getZ());
//circle = DetailDistanceUtil.getDistanceGenerationInverse(maxDistance);
generationRequestList.add(new GenerationRequest(levelPos, DetailDistanceUtil.getDistanceGenerationMode(levelPos.detailLevel)));
requestingFar--;
requesting--;
}
}
}
//====================================//
// get the closet generation requests //
//====================================//
// determine which points in the posListToGenerate
// should actually be queued to generate
for (GenerationRequest generationRequest : generationRequestList)
{
ChunkPos chunkPos = generationRequest.getChunkPos();
ChunkPos chunkPos = new ChunkPos(LevelPosUtil.getChunkPos(detailLevel,posX), LevelPosUtil.getChunkPos(detailLevel,posZ));
if (numberOfChunksWaitingToGenerate.get() < maxChunkGenRequests)
{
// prevent generating the same chunk multiple times
@@ -216,32 +140,16 @@ public class LodWorldGenerator
{
continue;
}
chunksToGen.add(generationRequest);
}
} // lod null and can generate more chunks
} // positions to generate
//=============================//
// start the LodNodeGenWorkers //
//=============================//
// issue #19
// TODO add a way for a server side mod to generate chunks requested here
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension);
// start chunk generation
for (GenerationRequest generationRequest : generationRequestList)
{
// don't add null chunkPos (which shouldn't happen anyway)
// or add more to the generation queue
ChunkPos chunkPos = generationRequest.getChunkPos();
if (chunkPos == null || numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests)
continue;
positionWaitingToBeGenerated.add(chunkPos);
numberOfChunksWaitingToGenerate.addAndGet(1);
LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, generationRequest.generationMode, renderer, lodBuilder, lodDim, serverWorld);
LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, DetailDistanceUtil.getDistanceGenerationMode(detailLevel), renderer, lodBuilder, lodDim, serverWorld);
WorldWorkerManager.addWorker(genWorker);
}
@@ -2,47 +2,96 @@ package com.seibel.lod.objects;
public class DataPoint
{
public final static int HEIGHT_SHIFT = 54;
public final static int DEPTH_SHIFT = 44;
public final static int RED_SHIFT = 36;
public final static int GREEN_SHIFT = 28;
public final static int BLUE_SHIFT = 20;
public final static int GEN_TYPE_SHIFT = 17;
public final static int LIGHT_SHIFT = 13;
public final static int EXISTENCE_SHIFT = 0;
public static short[] createDataPoint(int height, int depth, int red, int green, int blue)
public final static long HEIGHT_MASK = Long.parseUnsignedLong("1111111111", 2);
public final static long DEPTH_MASK = Long.parseUnsignedLong("1111111111", 2);
public final static long RED_MASK = Long.parseUnsignedLong("11111111", 2);
public final static long GREEN_MASK = Long.parseUnsignedLong("11111111", 2);
public final static long BLUE_MASK = Long.parseUnsignedLong("11111111", 2);
public final static long GEN_TYPE_MASK = Long.parseUnsignedLong("111", 2);
public final static long LIGHT_MASK = Long.parseUnsignedLong("1111", 2);
public final static long EXISTENCE_MASK = 1;
public static long createDataPoint(int height, int depth, int color)
{
return new short[]{(short) height, (short) depth, (short) red, (short) green, (short) blue};
int red = (getRed(color) << 16) & 0x00FF0000;
int green = (getGreen(color) << 8) & 0x0000FF00;
int blue = getBlue(color)& 0x000000FF;
return createDataPoint(height, depth, red, green, blue);
}
public static long createDataPoint(int height, int depth, int red, int green, int blue)
{
long dataPoint = 0;
dataPoint += (height & HEIGHT_MASK) << HEIGHT_SHIFT;
dataPoint += (depth & DEPTH_MASK) << DEPTH_SHIFT;
dataPoint += (red & RED_MASK) << RED_SHIFT;
dataPoint += (green & GREEN_MASK) << GREEN_SHIFT;
dataPoint += (blue & BLUE_MASK) << BLUE_SHIFT;
dataPoint += 1;
return dataPoint;
}
public static short getHeight(short[] dataPoint)
public static short getHeight(long dataPoint)
{
return dataPoint[0];
return (short) ((dataPoint >> HEIGHT_SHIFT) & HEIGHT_MASK);
}
public static short getDepth(short[] dataPoint)
public static short getDepth(long dataPoint)
{
return dataPoint[1];
return (short) ((dataPoint >> DEPTH_SHIFT) & DEPTH_MASK);
}
public static short getRed(short[] dataPoint)
public static short getRed(long dataPoint)
{
return dataPoint[2];
return (short) ((dataPoint >> RED_SHIFT) & RED_MASK);
}
public static short getGreen(short[] dataPoint)
public static short getGreen(long dataPoint)
{
return dataPoint[3];
return (short) ((dataPoint >> GREEN_SHIFT) & GREEN_MASK);
}
public static short getBlue(short[] dataPoint)
public static short getBlue(long dataPoint)
{
return dataPoint[4];
return (short) ((dataPoint >> BLUE_SHIFT) & BLUE_MASK);
}
public static short[] getHeightDepth(short[] dataPoint)
public static boolean doesItExist(long dataPoint)
{
return new short[]{dataPoint[0], dataPoint[1]};
return ((dataPoint & EXISTENCE_MASK) == 1);
}
public static int getColor(short[] dataPoint)
public static int getColor(long dataPoint)
{
int R = (dataPoint[2] << 16) & 0x00FF0000;
int G = (dataPoint[3] << 8) & 0x0000FF00;
int B = dataPoint[4] & 0x000000FF;
int R = (getRed(dataPoint) << 16) & 0x00FF0000;
int G = (getGreen(dataPoint) << 8) & 0x0000FF00;
int B = getBlue(dataPoint)& 0x000000FF;
return 0xFF000000 | R | G | B;
}
public static String toString(long dataPoint)
{
StringBuilder s = new StringBuilder();
s.append(getHeight(dataPoint));
s.append(" ");
s.append(getDepth(dataPoint));
s.append(" ");
s.append(getRed(dataPoint));
s.append(" ");
s.append(getBlue(dataPoint));
s.append(" ");
s.append(getGreen(dataPoint));
s.append('\n');
return s.toString();
}
}
@@ -11,61 +11,33 @@ public class LevelContainer implements Serializable
public final byte detailLevel;
public final byte[][][] colors;
public final long[][] data;
public final short[][] height;
public final short[][] depth;
public final boolean[][] dataExistence;
public LevelContainer(byte detailLevel, byte[][][] colors, short[][] height, short[][] depth, boolean[][] dataExistence)
public LevelContainer(byte detailLevel, long[][] data)
{
this.detailLevel = detailLevel;
this.colors = colors;
this.height = height;
this.depth = depth;
this.dataExistence = dataExistence;
this.data = data;
}
public LevelContainer(String data)
public LevelContainer(String inputString)
{
int index = 0;
int lastIndex = 0;
index = data.indexOf(DATA_DELIMITER, 0);
this.detailLevel = (byte) Integer.parseInt(data.substring(0, index));
index = inputString.indexOf(DATA_DELIMITER, 0);
this.detailLevel = (byte) Integer.parseInt(inputString.substring(0, index));
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
this.colors = new byte[size][size][3];
this.height = new short[size][size];
this.depth = new short[size][size];
this.dataExistence = new boolean[size][size];
int intCol;
this.data = new long[size][size];
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
intCol = Integer.parseInt(data.substring(lastIndex + 1, index), 16);
colors[x][z][0] = (byte) ((intCol >> 16) - 128);
colors[x][z][1] = (byte) ((intCol >> 8) - 128);
colors[x][z][2] = (byte) (intCol - 128);
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
height[x][z] = Short.parseShort(data.substring(lastIndex + 1, index), 16);
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
depth[x][z] = Short.parseShort(data.substring(lastIndex + 1, index), 16);
lastIndex = index;
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
dataExistence[x][z] = Boolean.parseBoolean(data.substring(lastIndex + 1, index));
index = inputString.indexOf(DATA_DELIMITER, lastIndex + 1);
data[x][z] = Long.parseLong(inputString.substring(lastIndex + 1, index), 16);
}
}
@@ -75,7 +47,6 @@ public class LevelContainer implements Serializable
public String toString()
{
StringBuilder stringBuilder = new StringBuilder();
int combinedCol;
int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel);
stringBuilder.append(detailLevel);
stringBuilder.append(DATA_DELIMITER);
@@ -83,15 +54,8 @@ public class LevelContainer implements Serializable
{
for (int z = 0; z < size; z++)
{
//Converting the colors to intColor and then to HEX
combinedCol = ((colors[x][z][0] + 128) << 16) | ((colors[x][z][1] + 128) << 8) | ((colors[x][z][2] + 128));
stringBuilder.append(Integer.toHexString(combinedCol));
stringBuilder.append(DATA_DELIMITER);
stringBuilder.append(Integer.toHexString(height[x][z] & 0xffff));
stringBuilder.append(DATA_DELIMITER);
stringBuilder.append(Integer.toHexString(depth[x][z] & 0xffff));
stringBuilder.append(DATA_DELIMITER);
stringBuilder.append(dataExistence[x][z]);
//Converting the dataToHex
stringBuilder.append(Long.toHexString(data[x][z]));
stringBuilder.append(DATA_DELIMITER);
}
}
@@ -1,7 +0,0 @@
package com.seibel.lod.objects.LevelPos;
public interface ImmutableLevelPos
{
public LevelPos getConvertedLevelPos(byte newDetailLevel);
public LevelPos getRegionModuleLevelPos();
}
@@ -1,415 +0,0 @@
package com.seibel.lod.objects.LevelPos;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.util.LodUtil;
import net.minecraft.util.math.ChunkPos;
import java.util.Comparator;
public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos, Comparable<LevelPos>
{
public byte detailLevel;
public int posX;
public int posZ;
public boolean flag;
public LevelPos()
{
}
public LevelPos(byte detailLevel, int posX, int posZ)
{
this.posX = posX;
this.posZ = posZ;
this.detailLevel = detailLevel;
}
/**
* this operation does not change the state
*/
public LevelPos getConvertedLevelPos(byte newDetailLevel)
{
if (newDetailLevel >= detailLevel)
{
int width = 1 << (newDetailLevel - detailLevel);
return new LevelPos(
newDetailLevel,
Math.floorDiv(posX, width),
Math.floorDiv(posZ, width));
} else
{
int width = 1 << (detailLevel - newDetailLevel);
return new LevelPos(
newDetailLevel,
posX * width,
posZ * width);
}
}
/**
* this operation does not change the state
*/
public LevelPos getRegionModuleLevelPos()
{
int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
return new LevelPos(
detailLevel,
Math.floorMod(posX, width),
Math.floorMod(posZ, width));
}
/**
* this operation changes the state
*/
public void convert(byte newDetailLevel)
{
if (newDetailLevel >= detailLevel)
{
int width = 1 << (newDetailLevel - detailLevel);
detailLevel = newDetailLevel;
posX = Math.floorDiv(posX, width);
posZ = Math.floorDiv(posZ, width);
} else
{
int width = 1 << (detailLevel - newDetailLevel);
detailLevel = newDetailLevel;
posX = posX * width;
posZ = posZ * width;
}
}
/**
* this operation changes the state
*/
public void performRegionModule()
{
int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
posX = Math.floorMod(posX, width);
posZ = Math.floorMod(posZ, width);
}
/**
* this operation changes the state
*/
public void applyOffset(int xOffset, int zOffset)
{
posX = posX + xOffset;
posX = posZ + zOffset;
}
/**
* this operation changes the state
*/
public void changeParameters(byte newDetailLevel, int newPosX, int newPosZ)
{
detailLevel = newDetailLevel;
posX = newPosX;
posZ = newPosZ;
}
public RegionPos getRegionPos()
{
int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
return new RegionPos(
Math.floorDiv(posX, width),
Math.floorDiv(posZ, width));
}
public int getRegionPosX()
{
int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
return Math.floorDiv(posX, width);
}
public int getRegionPosZ()
{
int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
return Math.floorDiv(posZ, width);
}
public int getChunkPosX()
{
if (LodUtil.CHUNK_DETAIL_LEVEL >= detailLevel)
{
int width = 1 << (LodUtil.CHUNK_DETAIL_LEVEL - detailLevel);
return Math.floorDiv(posX, width);
} else
{
int width = 1 << (detailLevel - LodUtil.CHUNK_DETAIL_LEVEL);
return posX * width;
}
}
public int getChunkPosZ()
{
if (LodUtil.CHUNK_DETAIL_LEVEL >= detailLevel)
{
int width = 1 << (LodUtil.CHUNK_DETAIL_LEVEL - detailLevel);
return Math.floorDiv(posZ, width);
} else
{
int width = 1 << (detailLevel - LodUtil.CHUNK_DETAIL_LEVEL);
return posZ * width;
}
}
public ChunkPos getChunkPos()
{
if (LodUtil.CHUNK_DETAIL_LEVEL >= detailLevel)
{
int width = 1 << (LodUtil.CHUNK_DETAIL_LEVEL - detailLevel);
return new ChunkPos(
Math.floorDiv(posX, width),
Math.floorDiv(posZ, width));
} else
{
int width = 1 << (detailLevel - LodUtil.CHUNK_DETAIL_LEVEL);
return new ChunkPos(
posX * width,
posZ * width);
}
}
/**
* TODO fix the region disappearing for a second
*/
public int maxDistance(int playerPosX, int playerPosZ, int regionPosX, int regionPosZ)
{
int width = 1 << detailLevel;
int startPosX = regionPosX * 512 + posX * width;
int startPosZ = regionPosZ * 512 + posZ * width;
int endPosX = startPosX + width;
int endPosZ = startPosZ + width;
int maxDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
return maxDistance;
}
public int maxDistance(int playerPosX, int playerPosZ)
{
int width = 1 << detailLevel;
int startPosX = posX * width;
int startPosZ = posZ * width;
int endPosX = startPosX + width;
int endPosZ = startPosZ + width;
int maxDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
return maxDistance;
}
public int minDistance(int playerPosX, int playerPosZ, int regionPosX, int regionPosZ)
{
int width = 1 << detailLevel;
int startPosX = regionPosX * 512 + posX * width;
int startPosZ = regionPosZ * 512 + posZ * width;
int endPosX = startPosX + width;
int endPosZ = startPosZ + width;
boolean inXArea = playerPosX >= startPosX && playerPosX <= endPosX;
boolean inZArea = playerPosZ >= startPosZ && playerPosZ <= endPosZ;
if (inXArea && inZArea)
{
return 0;
} else if (inXArea)
{
return Math.min(
Math.abs(playerPosZ - startPosZ),
Math.abs(playerPosZ - endPosZ)
);
} else if (inZArea)
{
return Math.min(
Math.abs(playerPosX - startPosX),
Math.abs(playerPosX - endPosX)
);
} else
{
int minDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
return minDistance;
}
}
public int minDistance(int playerPosX, int playerPosZ)
{
int width = 1 << detailLevel;
int startPosX = posX * width;
int startPosZ = posZ * width;
int endPosX = startPosX + width;
int endPosZ = startPosZ + width;
boolean inXArea = playerPosX >= startPosX && playerPosX <= endPosX;
boolean inZArea = playerPosZ >= startPosZ && playerPosZ <= endPosZ;
if (inXArea && inZArea)
{
return 0;
} else if (inXArea)
{
return Math.min(
Math.abs(playerPosZ - startPosZ),
Math.abs(playerPosZ - endPosZ)
);
} else if (inZArea)
{
return Math.min(
Math.abs(playerPosX - startPosX),
Math.abs(playerPosX - endPosX)
);
} else
{
int minDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)));
minDistance = Math.min(minDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
return minDistance;
}
}
public static LevelPosDistanceComparator getPosComparator(int playerPosX, int playerPosZ)
{
return new LevelPosDistanceComparator(playerPosX, playerPosZ);
}
public static LevelPosDetailComparator getPosAndDetailComparator(int playerPosX, int playerPosZ)
{
return new LevelPosDetailComparator(playerPosX, playerPosZ);
}
public static class LevelPosDistanceComparator implements Comparator<LevelPos>
{
int playerPosX;
int playerPosZ;
public LevelPosDistanceComparator(int playerPosX, int playerPosZ)
{
this.playerPosX = playerPosX;
this.playerPosZ = playerPosZ;
}
@Override
public int compare(LevelPos first, LevelPos second)
{
return Integer.compare(
first.minDistance(playerPosX, playerPosZ),
second.minDistance(playerPosX, playerPosZ));
}
}
public static class LevelPosDetailComparator implements Comparator<LevelPos>
{
int playerPosX;
int playerPosZ;
public LevelPosDetailComparator(int playerPosX, int playerPosZ)
{
this.playerPosX = playerPosX;
this.playerPosZ = playerPosZ;
}
@Override
public int compare(LevelPos first, LevelPos second)
{
int compareResult = Integer.compare(second.detailLevel, first.detailLevel);
if (compareResult == 0)
{
compareResult = Integer.compare(
first.minDistance(playerPosX, playerPosZ),
second.minDistance(playerPosX, playerPosZ));
}
return compareResult;
}
}
public static LevelPosComparator getComparator()
{
return new LevelPosComparator();
}
public static class LevelPosComparator implements Comparator<LevelPos>
{
@Override
public int compare(LevelPos first, LevelPos second)
{
int compareResult = Integer.compare(first.detailLevel, second.detailLevel);
if (compareResult == 0)
{
compareResult = Integer.compare(
first.posX,
second.posX);
}
if (compareResult == 0)
{
compareResult = Integer.compare(
first.posZ,
second.posZ);
}
return compareResult;
}
}
@Override
public int compareTo(LevelPos other)
{
int compareResult = Integer.compare(this.detailLevel, other.detailLevel);
if (compareResult == 0)
{
compareResult = Integer.compare(
this.posX,
other.posX);
}
if (compareResult == 0)
{
compareResult = Integer.compare(
this.posZ,
other.posZ);
}
return compareResult;
}
@Override
public LevelPos clone()
{
return new LevelPos(detailLevel, posX, posZ);
}
@Override
public int hashCode()
{
int hash = 7;
hash = 31 * hash + (int) detailLevel;
hash = 31 * hash + posX;
hash = 31 * hash + posZ;
return hash;
}
@Override
public boolean equals(Object other)
{
return (this.detailLevel == ((LevelPos) other).detailLevel &&
this.posX == ((LevelPos) other).posX &&
this.posZ == ((LevelPos) other).posZ);
}
@Override
public String toString()
{
String s = (detailLevel + " " + posX + " " + posZ);
return s;
}
}
@@ -1,14 +0,0 @@
package com.seibel.lod.objects.LevelPos;
import com.seibel.lod.util.LodUtil;
public interface MutableLevelPos
{
public void convert(byte newDetailLevel);
public void performRegionModule();
public void applyOffset(int xOffset, int zOffset);
public void changeParameters(byte newDetailLevel, int newPosX, int newPosZ);
}
@@ -37,11 +37,29 @@ public class LevelPosUtil
return new int[]{detailLevel, posX, posZ};
}
public static int[] createLevelPos(byte detailLevel, int posX, int posZ, int distance)
public static int convert(byte detailLevel, int pos, byte newDetailLevel)
{
return new int[]{detailLevel, posX, posZ, distance};
int width;
if (newDetailLevel >= detailLevel)
{
width = 1 << (newDetailLevel - detailLevel);
return Math.floorDiv(pos, width);
} else
{
width = 1 << (detailLevel - newDetailLevel);
return pos * width;
}
}
public static int getRegion(byte detailLevel, int pos)
{
return Math.floorDiv(pos, 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel));
}
public static int getRegionModule(byte detailLevel, int pos)
{
return Math.floorMod(pos, 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel));
}
public static byte getDetailLevel(int[] levelPos)
{
@@ -105,6 +123,11 @@ public class LevelPosUtil
return Math.floorDiv(getPosZ(levelPos), width);
}
public static int getChunkPos(byte detailLevel, int pos)
{
return convert(detailLevel,pos, LodUtil.CHUNK_DETAIL_LEVEL);
}
public static int getChunkPosX(int[] levelPos)
{
levelPos = convert(levelPos, LodUtil.CHUNK_DETAIL_LEVEL);
@@ -139,6 +162,23 @@ public class LevelPosUtil
return maxDistance;
}
public static int maxDistance(byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ, int xRegion, int zRegion)
{
int width = 1 << detailLevel;
int startPosX = xRegion * 512 + posX * width;
int startPosZ = zRegion * 512 + posZ * width;
int endPosX = startPosX + width;
int endPosZ = startPosZ + width;
int maxDistance = (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - startPosZ, 2));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - startPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - startPosZ, 2)));
maxDistance = Math.max(maxDistance, (int) Math.sqrt(Math.pow(playerPosX - endPosX, 2) + Math.pow(playerPosZ - endPosZ, 2)));
return maxDistance;
}
public static int minDistance(int[] levelPos, int playerPosX, int playerPosZ)
{
@@ -181,40 +221,24 @@ public class LevelPosUtil
}
}
public static int compareDistance(int posX, int posZ, int[] first, int[] second)
public static int compareDistance(int firstDistance, int secondDistance)
{
return Integer.compare(
minDistance(first, posX, posZ),
minDistance(second, posX, posZ));
firstDistance,
secondDistance);
}
public static int compareDistance(int[] first, int[] second)
{
return Integer.compare(
getDistance(first),
getDistance(second));
}
public static int compareLevelAndDistance(int[] first, int[] second)
public static int compareLevelAndDistance(byte firstDetail, int firstDistance, byte secondDetail, int secondDistance)
{
int compareResult = Integer.compare(getDetailLevel(second), getDetailLevel(first));
int compareResult = Integer.compare(
secondDetail,
firstDetail);
if (compareResult == 0)
{
compareResult = Integer.compare(
getDistance(first),
getDistance(second));
}
return compareResult;
}
public static int compareLevelAndDistance(int posX, int posZ, int[] first, int[] second)
{
int compareResult = Integer.compare(getDetailLevel(second), getDetailLevel(first));
if (compareResult == 0)
{
compareResult = Integer.compare(
minDistance(first, posX, posZ),
minDistance(second, posX, posZ));
firstDistance,
secondDistance);
}
return compareResult;
}
@@ -223,4 +247,8 @@ public class LevelPosUtil
{
return (getDetailLevel(levelPos) + " " + getPosX(levelPos) + " " + getPosZ(levelPos));
}
public static String toString(byte detailLevel, int posX, int posZ)
{
return (detailLevel + " " + posX + " " + posZ);
}
}
@@ -24,21 +24,22 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.seibel.lod.wrapper.MinecraftWrapper;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.handlers.LodDimensionFileHandler;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodThreadFactory;
import com.seibel.lod.util.LodUtil;
import com.seibel.lod.wrapper.MinecraftWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.DimensionType;
import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld;
import org.lwjgl.system.CallbackI;
/**
@@ -47,7 +48,7 @@ import net.minecraft.world.server.ServerWorld;
*
* @author Leonardo Amato
* @author James Seibel
* @version 9-6-2021
* @version 8-8-2021
*/
public class LodDimension
{
@@ -67,8 +68,10 @@ public class LodDimension
public volatile LodRegion regions[][];
public volatile boolean isRegionDirty[][];
public volatile boolean regen[][];
/** if true that means there are regions in this dimension
* that need to have their buffers rebuilt. */
/**
* if true that means there are regions in this dimension
* that need to have their buffers rebuilt.
*/
public volatile boolean regenDimension = false;
private volatile RegionPos center;
@@ -243,6 +246,8 @@ public class LodDimension
*/
public int getMinMemoryNeeded()
{
int regionX;
int regionZ;
int count = 0;
LodRegion region;
@@ -260,25 +265,29 @@ public class LodDimension
return count;
}
/**
* Gets the region at the given X and Z
* <br>
* Returns null if the region doesn't exist
* or is outside the loaded area.
*/
public LodRegion getRegion(LevelPos levelPos)
public LodRegion getRegion(byte detailLevel, int posX, int posZ)
{
int xRegion = LevelPosUtil.getRegion(detailLevel, posX);
int zRegion = LevelPosUtil.getRegion(detailLevel, posZ);
int xIndex = (xRegion - center.x) + halfWidth;
int zIndex = (zRegion - center.z) + halfWidth;
RegionPos regionPos = levelPos.getRegionPos();
int xIndex = (regionPos.x - center.x) + halfWidth;
int zIndex = (regionPos.z - center.z) + halfWidth;
if (!regionIsInRange(regionPos.x, regionPos.z))
throw new ArrayIndexOutOfBoundsException("Region for level pos " + levelPos + " out of range");
if (!regionIsInRange(xRegion, zRegion))
return null;
//throw new ArrayIndexOutOfBoundsException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " out of range");
else if (regions[xIndex][zIndex] == null)
throw new InvalidParameterException("Region for level pos " + levelPos + " not currently initialized");
else if (regions[xIndex][zIndex].getMinDetailLevel() > levelPos.detailLevel)
throw new InvalidParameterException("Region for level pos " + levelPos + " currently only reach level " + regions[xIndex][zIndex].getMinDetailLevel());
return null;
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " not currently initialized");
else if (regions[xIndex][zIndex].getMinDetailLevel() > detailLevel)
return null;
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " currently only reach level " + regions[xIndex][zIndex].getMinDetailLevel());
return regions[xIndex][zIndex];
}
@@ -288,15 +297,17 @@ public class LodDimension
* Returns null if the region doesn't exist
* or is outside the loaded area.
*/
public LodRegion getRegion(RegionPos regionPos)
public LodRegion getRegion(int regionPosX, int regionPosZ)
{
int xIndex = (regionPos.x - center.x) + halfWidth;
int zIndex = (regionPos.z - center.z) + halfWidth;
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
if (!regionIsInRange(regionPos.x, regionPos.z))
throw new ArrayIndexOutOfBoundsException("Region " + regionPos + " out of range");
if (!regionIsInRange(regionPosX, regionPosZ))
return null;
//throw new ArrayIndexOutOfBoundsException("Region " + regionPosX + " " + regionPosZ + " out of range");
else if (regions[xIndex][zIndex] == null)
throw new InvalidParameterException("Region " + regionPos + " not currently initialized");
return null;
//throw new InvalidParameterException("Region " + regionPosX + " " + regionPosZ + " not currently initialized");
return regions[xIndex][zIndex];
}
@@ -308,7 +319,7 @@ public class LodDimension
public synchronized void addOrOverwriteRegion(LodRegion newRegion) throws ArrayIndexOutOfBoundsException
{
int xIndex = (newRegion.regionPosX - center.x) + halfWidth;
int zIndex = (center.z - newRegion.regionPosZ) + halfWidth;
int zIndex = (newRegion.regionPosZ - center.z) + halfWidth;
if (!regionIsInRange(newRegion.regionPosX, newRegion.regionPosZ))
// out of range
@@ -323,7 +334,7 @@ public class LodDimension
*/
public void treeCutter(int playerPosX, int playerPosZ)
{
ChunkPos newPlayerChunk = (new LevelPos((byte) 0, playerPosX, playerPosZ)).getChunkPos();
ChunkPos newPlayerChunk = new ChunkPos(LevelPosUtil.getChunkPos((byte) 0, playerPosX), LevelPosUtil.getChunkPos((byte) 0, playerPosZ));
if (lastCutChunk == null)
lastCutChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1);
if (newPlayerChunk.x != lastCutChunk.x || newPlayerChunk.z != lastCutChunk.z)
@@ -336,7 +347,6 @@ public class LodDimension
int minDistance;
byte detail;
byte levelToCut;
LevelPos levelPos = new LevelPos();
for (int x = 0; x < regions.length; x++)
{
@@ -349,8 +359,7 @@ public class LodDimension
//if this is not the case w
if (regions[x][z] != null)
{
levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ);
minDistance = levelPos.minDistance(playerPosX, playerPosZ);
minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX, playerPosZ);
detail = DetailDistanceUtil.getDistanceTreeCutInverse(minDistance);
levelToCut = DetailDistanceUtil.getCutLodDetail(detail);
if (regions[x][z].getMinDetailLevel() > levelToCut)
@@ -373,7 +382,7 @@ public class LodDimension
public void treeGenerator(int playerPosX, int playerPosZ)
{
DistanceGenerationMode generationMode = LodConfig.CLIENT.worldGenerator.distanceGenerationMode.get();
ChunkPos newPlayerChunk = (new LevelPos((byte) 0, playerPosX, playerPosZ)).getChunkPos();
ChunkPos newPlayerChunk = new ChunkPos(LevelPosUtil.getChunkPos((byte) 0, playerPosX), LevelPosUtil.getChunkPos((byte) 0, playerPosZ));
if (lastGenChunk == null)
lastGenChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1);
@@ -388,20 +397,17 @@ public class LodDimension
int minDistance;
byte detail;
byte levelToGen;
LevelPos levelPos = new LevelPos();
for (int x = 0; x < regions.length; x++)
{
for (int z = 0; z < regions.length; z++)
{
regionX = (x + center.x) - halfWidth;
regionZ = (z + center.z) - halfWidth;
levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ);
final RegionPos regionPos = new RegionPos(regionX, regionZ);
region = regions[x][z];
//We require that the region we are checking is loaded with at least this level
levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ);
minDistance = levelPos.minDistance(playerPosX, playerPosZ);
minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX, playerPosZ);
detail = DetailDistanceUtil.getDistanceTreeGenInverse(minDistance);
levelToGen = DetailDistanceUtil.getLodGenDetail(detail).detailLevel;
if (region == null || region.getGenerationMode() != generationMode)
@@ -437,32 +443,31 @@ public class LodDimension
* stored in the LOD. If an LOD already exists at the given
* coordinates it will be overwritten.
*/
public synchronized Boolean addData(LevelPos levelPos, short[] lodDataPoint, boolean dontSave, boolean serverQuality)
public synchronized Boolean addData(byte detailLevel, int posX, int posZ, long lodDataPoint, boolean dontSave, boolean serverQuality)
{
// don't continue if the region can't be saved
RegionPos regionPos = levelPos.getRegionPos();
if (!regionIsInRange(regionPos.x, regionPos.z))
{
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return false;
}
LodRegion region = getRegion(levelPos);
boolean nodeAdded = region.addData(levelPos, lodDataPoint, serverQuality);
boolean nodeAdded = region.addData(detailLevel, posX, posZ, lodDataPoint, serverQuality);
// only save valid LODs to disk
if (!dontSave && fileHandler != null)
{
try
{
// mark the region as dirty so it will be saved to disk
int xIndex = (regionPos.x - center.x) + halfWidth;
int zIndex = (regionPos.z - center.z) + halfWidth;
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
isRegionDirty[xIndex][zIndex] = true;
regen[xIndex][zIndex] = true;
regenDimension = true;
} catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
// This method was probably called when the dimension was changing size.
// Hopefully this shouldn't be an issue.
}
@@ -470,7 +475,8 @@ public class LodDimension
return nodeAdded;
}
public void setToRegen(int xRegion, int zRegion){
public void setToRegen(int xRegion, int zRegion)
{
int xIndex = (xRegion - center.x) + halfWidth;
int zIndex = (zRegion - center.z) + halfWidth;
regen[xIndex][zIndex] = true;
@@ -481,32 +487,26 @@ public class LodDimension
*
* @return list of quadTrees
*/
public void getDataToGenerate(ConcurrentMap<LevelPos, MutableBoolean> dataToGenerate, int playerPosX, int playerPosZ)
public PosToGenerateContainer getDataToGenerate(byte farDetail, int maxDataToGenerate, double farRatio, int playerPosX, int playerPosZ)
{
PosToGenerateContainer posToGenerate = new PosToGenerateContainer(farDetail, maxDataToGenerate, (int) (maxDataToGenerate * farRatio), playerPosX, playerPosZ);
int n = regions.length;
int xIndex;
int zIndex;
LodRegion region;
RegionPos regionPos;
for (int xRegion = 0; xRegion < n; xRegion++)
{
for (int zRegion = 0; zRegion < n; zRegion++)
{
try
{
xIndex = (xRegion + center.x) - halfWidth;
zIndex = (zRegion + center.z) - halfWidth;
regionPos = new RegionPos(xIndex, zIndex);
region = getRegion(regionPos);
region.getDataToGenerate(dataToGenerate, playerPosX, playerPosZ);
xIndex = (xRegion + center.x) - halfWidth;
zIndex = (zRegion + center.z) - halfWidth;
region = getRegion(xIndex, zIndex);
if (region != null)
region.getDataToGenerate(posToGenerate, playerPosX, playerPosZ);
} catch (Exception e)
{
//e.printStackTrace();
}
}
}
return posToGenerate;
}
/**
@@ -514,33 +514,11 @@ public class LodDimension
*
* @return list of nodes
*/
public void getDataToRender(ConcurrentMap<LevelPos, MutableBoolean> dataToRender, RegionPos regionPos, int playerPosX, int playerPosZ)
public void getDataToRender(PosToRenderContainer posToRender, RegionPos regionPos, int playerPosX, int playerPosZ)
{
try
{
LodRegion region = getRegion(regionPos);
region.getDataToRender(dataToRender, playerPosX, playerPosZ);
} catch (NullPointerException e)
{
System.out.println(regionPos);
e.printStackTrace();
} catch (Exception e)
{
//e.printStackTrace();
}
}
/**
* Get the LodNodeData at the given X and Z coordinates
* in this dimension.
* <br>
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public short[] getData(ChunkPos chunkPos)
{
LevelPos levelPos = new LevelPos(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.x, chunkPos.z);
return getData(levelPos);
LodRegion region = getRegion(regionPos.x, regionPos.z);
if (region != null)
region.getDataToRender(posToRender, playerPosX, playerPosZ);
}
/**
@@ -550,26 +528,19 @@ public class LodDimension
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public short[] getData(LevelPos levelPos)
public long getData(byte detailLevel, int posX, int posZ)
{
if (levelPos.detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + levelPos.detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
try
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
LodRegion region = getRegion(levelPos);
if (region == null)
{
return null;
}
return region.getData(levelPos);
} catch (Exception e)
{
return null;
return 0;
}
return region.getData(detailLevel, posX, posZ);
}
@@ -580,40 +551,34 @@ public class LodDimension
* Returns null if the LodChunk doesn't exist or
* is outside the loaded area.
*/
public void updateData(LevelPos levelPos)
public void updateData(byte detailLevel, int posX, int posZ)
{
if (levelPos.detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + levelPos.detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(levelPos);
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return;
}
region.updateArea(levelPos);
region.updateArea(detailLevel, posX, posZ);
}
/**
* return true if and only if the node at that position exist
*/
public boolean doesDataExist(LevelPos levelPos)
public boolean doesDataExist(byte detailLevel, int posX, int posZ)
{
try
{
LodRegion region = getRegion(levelPos);
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return false;
}
return region.doesDataExist(levelPos.clone());
} catch (Exception e)
if (region == null)
{
return false;
}
return region.doesDataExist(detailLevel, posX, posZ);
}
/**
@@ -716,7 +681,6 @@ public class LodDimension
}
stringBuilder.append("\n");
}
System.out.println(stringBuilder);
return stringBuilder.toString();
}
}
@@ -1,14 +1,8 @@
package com.seibel.lod.objects;
import java.io.Serializable;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodUtil;
@@ -20,24 +14,19 @@ import com.seibel.lod.util.LodUtil;
* 0 for x, 1 for y, 2 for z in 3D
*/
public class LodRegion implements Serializable
public class LodRegion
{
//x coord,
private byte minDetailLevel;
private static final byte POSSIBLE_LOD = 10;
private int numberOfPoints;
//private int numberOfPoints;
private DistanceGenerationMode generationMode;
//For each of the following field the first slot is for the level of detail
//Important: byte have a [-128, 127] range. When converting from or to int a 128 should be added or removed
//If there is a bug with color then it's probably caused by this.
//in the future other fields like transparency and light level could be added
private byte[][][][] colors;
private short[][][] height;
private short[][][] depth;
private boolean[][][] dataExistence;
private long[][][] data;
public final int regionPosX;
@@ -50,42 +39,18 @@ public class LodRegion implements Serializable
this.regionPosZ = regionPos.z;
this.minDetailLevel = levelContainer.detailLevel;
//Array of matrices of arrays
colors = new byte[POSSIBLE_LOD][][][];
//Arrays of matrices
height = new short[POSSIBLE_LOD][][];
depth = new short[POSSIBLE_LOD][][];
dataExistence = new boolean[POSSIBLE_LOD][][];
data = new long[POSSIBLE_LOD][][];
colors[minDetailLevel] = levelContainer.colors;
height[minDetailLevel] = levelContainer.height;
depth[minDetailLevel] = levelContainer.depth;
dataExistence[minDetailLevel] = levelContainer.dataExistence;
data[minDetailLevel] = levelContainer.data;
//Initialize all the different matrices
for (byte lod = (byte) (minDetailLevel + 1); lod <= LodUtil.REGION_DETAIL_LEVEL; lod++)
{
int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod);
colors[lod] = new byte[size][size][3];
height[lod] = new short[size][size];
depth[lod] = new short[size][size];
dataExistence[lod] = new boolean[size][size];
}
int width;
LevelPos levelPos = new LevelPos();
for (byte tempLod = (byte) (minDetailLevel + 1); tempLod <= LodUtil.REGION_DETAIL_LEVEL; tempLod++)
{
width = 1 << (LodUtil.REGION_DETAIL_LEVEL - tempLod);
for (int x = 0; x < width; x++)
{
for (int z = 0; z < width; z++)
{
levelPos.changeParameters(tempLod, x, z);
update(levelPos);
}
}
data[lod] = new long[size][size];
}
updateArea(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ);
}
public LodRegion(byte minDetailLevel, RegionPos regionPos, DistanceGenerationMode generationMode)
@@ -95,23 +60,14 @@ public class LodRegion implements Serializable
this.regionPosX = regionPos.x;
this.regionPosZ = regionPos.z;
//Array of matrices of arrays
colors = new byte[POSSIBLE_LOD][][][];
//Arrays of matrices
height = new short[POSSIBLE_LOD][][];
depth = new short[POSSIBLE_LOD][][];
dataExistence = new boolean[POSSIBLE_LOD][][];
data = new long[POSSIBLE_LOD][][];
//Initialize all the different matrices
for (byte lod = minDetailLevel; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++)
{
int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - lod);
colors[lod] = new byte[size][size][3];
height[lod] = new short[size][size];
depth[lod] = new short[size][size];
dataExistence[lod] = new boolean[size][size];
data[lod] = new long[size][size];
}
}
@@ -119,26 +75,21 @@ public class LodRegion implements Serializable
/**
* This method can be used to insert data into the LodRegion
*
* @param levelPos
* @param dataPoint
* @return
*/
public boolean addData(LevelPos levelPos, short[] dataPoint, boolean serverQuality)
public boolean addData(byte detailLevel, int posX, int posZ, long dataPoint, boolean serverQuality)
{
levelPos.performRegionModule();
if (!doesDataExist(levelPos) || serverQuality)
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
if (!doesDataExist(detailLevel, posX, posZ) || serverQuality)
{
//update the number of node present
if (this.dataExistence[levelPos.detailLevel][levelPos.posX][levelPos.posZ]) numberOfPoints++;
//if (!doesDataExist(detailLevel, posX, posZ)) numberOfPoints++;
//add the node data
this.height[levelPos.detailLevel][levelPos.posX][levelPos.posZ] = DataPoint.getHeight(dataPoint);
this.depth[levelPos.detailLevel][levelPos.posX][levelPos.posZ] = DataPoint.getDepth(dataPoint);
this.colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][0] = (byte) (DataPoint.getRed(dataPoint) - 128);
this.colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][1] = (byte) (DataPoint.getGreen(dataPoint) - 128);
this.colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][2] = (byte) (DataPoint.getBlue(dataPoint) - 128);
this.dataExistence[levelPos.detailLevel][levelPos.posX][levelPos.posZ] = true;
this.data[detailLevel][posX][posZ] = dataPoint;
return true;
} else
{
@@ -149,18 +100,13 @@ public class LodRegion implements Serializable
/**
* This method will return the data in the position relative to the level of detail
*
* @param levelPos
* @return the data at the relative pos and level
*/
public short[] getData(LevelPos levelPos)
public long getData(byte detailLevel, int posX, int posZ)
{
levelPos = levelPos.getRegionModuleLevelPos();
return new short[]{height[levelPos.detailLevel][levelPos.posX][levelPos.posZ],
depth[levelPos.detailLevel][levelPos.posX][levelPos.posZ],
(short) (colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][0] + 128),
(short) (colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][1] + 128),
(short) (colors[levelPos.detailLevel][levelPos.posX][levelPos.posZ][2] + 128)
};
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return data[detailLevel][posX][posZ];
}
/**
@@ -168,25 +114,21 @@ public class LodRegion implements Serializable
*
* @return
*/
public void getDataToGenerate(ConcurrentMap<LevelPos, MutableBoolean> dataToGenerate, int playerPosX, int playerPosZ)
public void getDataToGenerate(PosToGenerateContainer posToGenerate, int playerPosX, int playerPosZ)
{
LevelPos levelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, 0, 0);
getDataToGenerate(dataToGenerate, levelPos, playerPosX, playerPosZ);
getDataToGenerate(posToGenerate, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ);
}
private void getDataToGenerate(ConcurrentMap<LevelPos, MutableBoolean> dataToGenerate, LevelPos levelPos, int playerPosX, int playerPosZ)
private void getDataToGenerate(PosToGenerateContainer posToGenerate, byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ)
{
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - levelPos.detailLevel);
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
//here i calculate the the LevelPos is in range
//This is important to avoid any kind of hole in the generation
int minDistance = levelPos.minDistance(playerPosX, playerPosZ, regionPosX, regionPosZ);
//nt minDistance = LevelPosUtil.minDistance(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size, playerPosX, playerPosZ);
int maxDistance = LevelPosUtil.maxDistance(detailLevel, posX, posZ, playerPosX, playerPosZ, regionPosX, regionPosZ);
int posX = levelPos.posX;
int posZ = levelPos.posZ;
byte detailLevel = levelPos.detailLevel;
byte childDetailLevel = (byte) (detailLevel - 1);
int childPosX = posX * 2;
int childPosZ = posZ * 2;
@@ -194,21 +136,14 @@ public class LodRegion implements Serializable
int childSize = 1 << (LodUtil.REGION_DETAIL_LEVEL - childDetailLevel);
//we have reached the target detail level
if (DetailDistanceUtil.getDistanceGenerationInverse(minDistance) > detailLevel)
if (DetailDistanceUtil.getDistanceGenerationInverse(maxDistance) > detailLevel)
{
return;
} else if (DetailDistanceUtil.getDistanceGenerationInverse(minDistance) == detailLevel)
} else if (DetailDistanceUtil.getDistanceGenerationInverse(maxDistance) == detailLevel)
{
if (!doesDataExist(levelPos))
if (!doesDataExist(detailLevel, posX, posZ))
{
levelPos.changeParameters(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size);
if (dataToGenerate.containsKey(levelPos))
{
dataToGenerate.get(levelPos).setTrue();
} else
{
dataToGenerate.put(levelPos.clone(), new MutableBoolean(true));
}
posToGenerate.addPosToGenerate(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size);
}
} else
{
@@ -221,19 +156,11 @@ public class LodRegion implements Serializable
{
for (int z = 0; z <= 1; z++)
{
levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x, childPosZ + z);
if (!doesDataExist(levelPos))
if (!doesDataExist(childDetailLevel, childPosX + x, childPosZ + z))
{
num++;
levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x + regionPosX * childSize, childPosZ + z + regionPosZ * childSize);
if (dataToGenerate.containsKey(levelPos))
{
dataToGenerate.get(levelPos).setTrue();
} else
{
dataToGenerate.put(levelPos.clone(), new MutableBoolean(true));
}
posToGenerate.addPosToGenerate(childDetailLevel, childPosX + x + regionPosX * childSize, childPosZ + z + regionPosZ * childSize);
}
}
}
@@ -245,8 +172,7 @@ public class LodRegion implements Serializable
{
for (int z = 0; z <= 1; z++)
{
levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x, childPosZ + z);
getDataToGenerate(dataToGenerate, levelPos, playerPosX, playerPosZ);
getDataToGenerate(posToGenerate, childDetailLevel, childPosX + x, childPosZ + z, playerPosX, playerPosZ);
}
}
}
@@ -255,21 +181,12 @@ public class LodRegion implements Serializable
{
if (DetailDistanceUtil.getLodGenDetail(childDetailLevel).detailLevel <= (childDetailLevel))
{
levelPos.changeParameters(detailLevel, posX, posZ);
levelPos.convert(childDetailLevel);
if (!doesDataExist(levelPos))
if (!doesDataExist(childDetailLevel, childPosX, childPosZ))
{
levelPos.changeParameters(levelPos.detailLevel, levelPos.posX + regionPosX * childSize, levelPos.posZ + regionPosZ * childSize);
if (dataToGenerate.containsKey(levelPos))
{
dataToGenerate.get(levelPos).setTrue();
} else
{
dataToGenerate.put(levelPos.clone(), new MutableBoolean(true));
}
posToGenerate.addPosToGenerate(childDetailLevel, childPosX + regionPosX * childSize, childPosZ + regionPosZ * childSize);
} else
{
getDataToGenerate(dataToGenerate, levelPos, playerPosX, playerPosZ);
getDataToGenerate(posToGenerate, childDetailLevel, childPosX, childPosZ, playerPosX, playerPosZ);
}
}
}
@@ -280,60 +197,41 @@ public class LodRegion implements Serializable
/**
* @return
*/
public void getDataToRender(ConcurrentMap<LevelPos, MutableBoolean> dataToRender, int playerPosX, int playerPosZ)
public void getDataToRender(PosToRenderContainer posToRender, int playerPosX, int playerPosZ)
{
LevelPos levelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, 0, 0);
getDataToRender(dataToRender, levelPos, playerPosX, playerPosZ);
getDataToRender(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ);
}
/**
* @return
*/
private void getDataToRender(ConcurrentMap<LevelPos, MutableBoolean> dataToRender, LevelPos levelPos, int playerPosX, int playerPosZ)
private void getDataToRender(PosToRenderContainer posToRender, byte detailLevel, int posX, int posZ, int playerPosX, int playerPosZ)
{
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - levelPos.detailLevel);
int posX = levelPos.posX;
int posZ = levelPos.posZ;
byte detailLevel = levelPos.detailLevel;
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
//here i calculate the the LevelPos is in range
//This is important to avoid any kind of hole in the rendering
int maxDistance = levelPos.maxDistance(playerPosX, playerPosZ, regionPosX, regionPosZ);
int maxDistance = LevelPosUtil.maxDistance(detailLevel, posX, posZ, playerPosX, playerPosZ, regionPosX, regionPosZ);
byte supposedLevel = DetailDistanceUtil.getLodDrawDetail(DetailDistanceUtil.getDistanceRenderingInverse(maxDistance));
if (supposedLevel > detailLevel)
return;
else if (supposedLevel == detailLevel)
{
if (dataToRender.containsKey(levelPos))
{
levelPos.changeParameters(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size);
try
{
dataToRender.get(levelPos).setTrue();
}catch (Exception e){
/*TODO Fix this exception*/
// This seems to happen more often when using an elytra in an amplified world
// maybe it has something to do with the dimensions moving?
ClientProxy.LOGGER.error("getDataToRender had a error at " + levelPos.getRegionPos() + ". Exception: " + e.getMessage());
dataToRender.put(new LevelPos(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size), new MutableBoolean(true));
}
} else
{
dataToRender.put(new LevelPos(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size), new MutableBoolean(true));
}
posToRender.addPosToRender(detailLevel,
posX + regionPosX * size,
posZ + regionPosZ * size);
} else //case where (detailLevel > supposedLevel)
{
int childPosX = posX * 2;
int childPosZ = posZ * 2;
byte childDetailLevel = (byte) (detailLevel - 1);
int childrenCount = 0;
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
{
levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x, childPosZ + z);
if (doesDataExist(levelPos)) childrenCount++;
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z)) childrenCount++;
}
}
@@ -344,68 +242,50 @@ public class LodRegion implements Serializable
{
for (int z = 0; z <= 1; z++)
{
levelPos.changeParameters((byte) (detailLevel - 1), childPosX + x, childPosZ + z);
getDataToRender(dataToRender, levelPos, playerPosX, playerPosZ);
getDataToRender(posToRender, childDetailLevel, childPosX + x, childPosZ + z, playerPosX, playerPosZ);
}
}
} else
{
levelPos.changeParameters(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size);
if (dataToRender.containsKey(levelPos))
{
if (dataToRender.get(levelPos) == null)
dataToRender.replace(levelPos, new MutableBoolean());
dataToRender.get(levelPos).setTrue();
} else
{
dataToRender.put(new LevelPos(detailLevel, posX + regionPosX * size, posZ + regionPosZ * size), new MutableBoolean(true));
}
posToRender.addPosToRender(detailLevel,
posX + regionPosX * size,
posZ + regionPosZ * size);
}
}
}
/**
* @param levelPos
*/
public void updateArea(LevelPos levelPos)
public void updateArea(byte detailLevel, int posX, int posZ)
{
int width;
int startX;
int startZ;
byte detailLevel = levelPos.detailLevel;
int posX = levelPos.posX;
int posZ = levelPos.posZ;
for (byte bottom = (byte) (minDetailLevel + 1); bottom <= detailLevel; bottom++)
{
levelPos.convert(bottom);
startX = levelPos.posX;
startZ = levelPos.posZ;
startX = LevelPosUtil.convert(detailLevel, posX, bottom);
startZ = LevelPosUtil.convert(detailLevel, posZ, bottom);
width = 1 << (detailLevel - bottom);
for (int x = 0; x < width; x++)
{
for (int z = 0; z < width; z++)
{
levelPos.changeParameters(bottom, startX + x, startZ + z);
update(levelPos);
update(bottom, startX + x, startZ + z);
}
}
levelPos.changeParameters(detailLevel, posX, posZ);
}
for (byte tempLod = (byte) (detailLevel + 1); tempLod <= LodUtil.REGION_DETAIL_LEVEL; tempLod++)
for (byte up = (byte) (detailLevel + 1); up <= LodUtil.REGION_DETAIL_LEVEL; up++)
{
levelPos.convert(tempLod);
update(levelPos);
update(up,
LevelPosUtil.convert(detailLevel, posX, up),
LevelPosUtil.convert(detailLevel, posZ, up));
}
}
/**
* @param levelPos
*/
private void update(LevelPos levelPos)
private void update(byte detailLevel, int posX, int posZ)
{
levelPos.performRegionModule();
int numberOfChildren = 0;
int numberOfVoidChildren = 0;
@@ -414,32 +294,30 @@ public class LodRegion implements Serializable
int tempBlue = 0;
int tempHeight = 0;
int tempDepth = 0;
int newPosX;
int newPosZ;
byte newDetailLevel;
int detailLevel = levelPos.detailLevel;
int posX = levelPos.posX;
int posZ = levelPos.posZ;
int childPosX;
int childPosZ;
byte childDetailLevel;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
for (int x = 0; x <= 1; x++)
{
for (int z = 0; z <= 1; z++)
{
newPosX = 2 * posX + x;
newPosZ = 2 * posZ + z;
newDetailLevel = (byte) (detailLevel - 1);
levelPos.changeParameters(newDetailLevel, newPosX, newPosZ);
if (doesDataExist(levelPos))
childPosX = 2 * posX + x;
childPosZ = 2 * posZ + z;
childDetailLevel = (byte) (detailLevel - 1);
if (doesDataExist(childDetailLevel, childPosX, childPosZ))
{
if (height[newDetailLevel][newPosX][newPosZ] != LodBuilder.DEFAULT_HEIGHT
&& depth[newDetailLevel][newPosX][newPosZ] != LodBuilder.DEFAULT_DEPTH)
if (DataPoint.getHeight(data[childDetailLevel][childPosX][childPosZ]) != LodBuilder.DEFAULT_HEIGHT
&& DataPoint.getDepth(data[childDetailLevel][childPosX][childPosZ]) != LodBuilder.DEFAULT_DEPTH)
{
numberOfChildren++;
tempRed += colors[newDetailLevel][newPosX][newPosZ][0];
tempGreen += colors[newDetailLevel][newPosX][newPosZ][1];
tempBlue += colors[newDetailLevel][newPosX][newPosZ][2];
tempHeight += height[newDetailLevel][newPosX][newPosZ];
tempDepth += depth[newDetailLevel][newPosX][newPosZ];
tempRed += DataPoint.getRed(data[childDetailLevel][childPosX][childPosZ]);
tempGreen += DataPoint.getGreen(data[childDetailLevel][childPosX][childPosZ]);
tempBlue += DataPoint.getBlue(data[childDetailLevel][childPosX][childPosZ]);
tempHeight += DataPoint.getHeight(data[childDetailLevel][childPosX][childPosZ]);
tempDepth += DataPoint.getDepth(data[childDetailLevel][childPosX][childPosZ]);
} else
{
// void children have the default height (most likely -1)
@@ -449,42 +327,34 @@ public class LodRegion implements Serializable
}
}
}
if (numberOfChildren > 0)
{
colors[detailLevel][posX][posZ][0] = (byte) (tempRed / numberOfChildren);
colors[detailLevel][posX][posZ][1] = (byte) (tempGreen / numberOfChildren);
colors[detailLevel][posX][posZ][2] = (byte) (tempBlue / numberOfChildren);
height[detailLevel][posX][posZ] = (short) (tempHeight / numberOfChildren);
depth[detailLevel][posX][posZ] = (short) (tempDepth / numberOfChildren);
dataExistence[detailLevel][posX][posZ] = true;
tempRed = tempRed / numberOfChildren;
tempGreen = tempGreen / numberOfChildren;
tempBlue = tempBlue / numberOfChildren;
tempHeight = tempHeight / numberOfChildren;
tempDepth = tempDepth / numberOfChildren;
} else if (numberOfVoidChildren > 0)
{
colors[detailLevel][posX][posZ][0] = (byte) 0;
colors[detailLevel][posX][posZ][1] = (byte) 0;
colors[detailLevel][posX][posZ][2] = (byte) 0;
height[detailLevel][posX][posZ] = LodBuilder.DEFAULT_HEIGHT;
depth[detailLevel][posX][posZ] = LodBuilder.DEFAULT_DEPTH;
dataExistence[detailLevel][posX][posZ] = true;
tempRed = (byte) 0;
tempGreen = (byte) 0;
tempBlue = (byte) 0;
tempHeight = LodBuilder.DEFAULT_HEIGHT;
tempDepth = LodBuilder.DEFAULT_DEPTH;
}
data[detailLevel][posX][posZ] = DataPoint.createDataPoint(tempHeight, tempDepth, tempRed, tempGreen, tempBlue);
}
/**
* @param levelPos
* @return
*/
public boolean doesDataExist(LevelPos levelPos)
public boolean doesDataExist(byte detailLevel, int posX, int posZ)
{
try
{
levelPos = levelPos.getRegionModuleLevelPos();
return dataExistence[levelPos.detailLevel][levelPos.posX][levelPos.posZ];
} catch (NullPointerException e)
{
return false;
}
if(detailLevel < minDetailLevel) return false;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return DataPoint.doesItExist(data[detailLevel][posX][posZ]);
}
/**
@@ -512,7 +382,7 @@ public class LodRegion implements Serializable
{
throw new IllegalArgumentException("getLevel asked for a level that does not exist: minimum " + minDetailLevel + " level requested " + detailLevel);
}
return new LevelContainer(detailLevel, colors[detailLevel], height[detailLevel], depth[detailLevel], dataExistence[detailLevel]);
return new LevelContainer(detailLevel, data[detailLevel]);
}
/**
@@ -525,10 +395,7 @@ public class LodRegion implements Serializable
throw new IllegalArgumentException("addLevel requires a level that is at least the minimum level of the region -1 ");
}
if (levelContainer.detailLevel == minDetailLevel - 1) minDetailLevel = levelContainer.detailLevel;
colors[levelContainer.detailLevel] = levelContainer.colors;
height[levelContainer.detailLevel] = levelContainer.height;
depth[levelContainer.detailLevel] = levelContainer.depth;
dataExistence[levelContainer.detailLevel] = levelContainer.dataExistence;
data[levelContainer.detailLevel] = levelContainer.data;
}
@@ -541,10 +408,7 @@ public class LodRegion implements Serializable
{
for (byte tempLod = 0; tempLod < detailLevel; tempLod++)
{
colors[tempLod] = new byte[0][0][0];
height[tempLod] = new short[0][0];
depth[tempLod] = new short[0][0];
dataExistence[tempLod] = new boolean[0][0];
data[tempLod] = new long[0][0];
}
minDetailLevel = detailLevel;
}
@@ -560,10 +424,7 @@ public class LodRegion implements Serializable
for (byte tempLod = detailLevel; tempLod < minDetailLevel; tempLod++)
{
int size = (short) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - tempLod);
colors[tempLod] = new byte[size][size][3];
height[tempLod] = new short[size][size];
depth[tempLod] = new short[size][size];
dataExistence[tempLod] = new boolean[size][size];
data[tempLod] = new long[size][size];
}
minDetailLevel = detailLevel;
}
@@ -1,7 +1,5 @@
package com.seibel.lod.objects;
import org.lwjgl.system.CallbackI;
public class PosToGenerateContainer
{
private int playerPosX;
@@ -27,20 +25,10 @@ public class PosToGenerateContainer
posToGenerate = new int[maxDataToGenerate][4];
}
public void addPosToGenerate(int[] levelPos)
{
addPosToGenerate(LevelPosUtil.getDetailLevel(levelPos), LevelPosUtil.getPosX(levelPos), LevelPosUtil.getPosZ(levelPos));
}
public void addPosToGenerate(byte detailLevel, int posX, int posZ)
{
int distance = LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ);
int index;
int[] tempPos = new int[]{
detailLevel,
posX,
posZ,
distance};
if (detailLevel >= farMinDetail)
{//We are introducing a position in the far array
if (farSize < maxFarSize)
@@ -53,26 +41,42 @@ public class PosToGenerateContainer
maxNearSize--;
}
index = posToGenerate.length - farSize;
while (index < posToGenerate.length - 1 && LevelPosUtil.compareLevelAndDistance(tempPos, posToGenerate[index + 1]) <= 0)
while (index < posToGenerate.length - 1 && LevelPosUtil.compareLevelAndDistance(detailLevel, distance, (byte) posToGenerate[index + 1][0], posToGenerate[index + 1][3]) <= 0)
{
posToGenerate[index] = posToGenerate[index + 1];
posToGenerate[index][0] = posToGenerate[index + 1][0];
posToGenerate[index][1] = posToGenerate[index + 1][1];
posToGenerate[index][2] = posToGenerate[index + 1][2];
posToGenerate[index][3] = posToGenerate[index + 1][3];
index++;
}
if (index <= posToGenerate.length - 1)
posToGenerate[index] = tempPos;
{
posToGenerate[index][0] = detailLevel + 1;
posToGenerate[index][1] = posX;
posToGenerate[index][2] = posZ;
posToGenerate[index][3] = distance;
}
} else
{//We are introducing a position in the near array
if (nearSize < maxNearSize)
nearSize++;
index = nearSize - 1;
while (index > 0 && LevelPosUtil.compareDistance(tempPos, posToGenerate[index - 1]) <= 0)
while (index > 0 && LevelPosUtil.compareDistance(distance, posToGenerate[index - 1][3]) <= 0)
{
posToGenerate[index] = posToGenerate[index - 1];
posToGenerate[index][0] = posToGenerate[index - 1][0];
posToGenerate[index][1] = posToGenerate[index - 1][1];
posToGenerate[index][2] = posToGenerate[index - 1][2];
posToGenerate[index][3] = posToGenerate[index - 1][3];
index--;
}
if (index >= 0)
posToGenerate[index] = tempPos;
{
posToGenerate[index][0] = detailLevel + 1;
posToGenerate[index][1] = posX;
posToGenerate[index][2] = posZ;
posToGenerate[index][3] = distance;
}
}
}
@@ -84,6 +88,10 @@ public class PosToGenerateContainer
public int[] getNthPos(int n)
{
/*if(n < farSize)
return posToGenerate[maxSize - n - 1];
else
return posToGenerate[n - farSize];*/
int index;
if (n > farSize * 2)
index = n - farSize;
@@ -1,40 +1,75 @@
package com.seibel.lod.objects;
import com.seibel.lod.util.LodUtil;
import java.util.Arrays;
public class PosToRenderContainer
{
private byte minDetail;
public byte minDetail;
private int regionPosX;
private int regionPosZ;
private int numberOfPosToRender;
private int[][] posToRender;
/*TODO this population matrix could be converted to boolean to improve memory use*/
private byte[][] population;
public PosToRenderContainer(byte minDetail)
public PosToRenderContainer(byte minDetail, int regionPosX, int regionPosZ)
{
this.minDetail = minDetail;
this.numberOfPosToRender = 0;
posToRender = new int[1][4];
this.regionPosX = regionPosX;
this.regionPosZ = regionPosZ;
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - minDetail);
posToRender = new int[size*size][3];
population = new byte[size][size];
}
public void addPosToRender(int[] levelPos)
public void addPosToRender(byte detailLevel, int posX, int posZ)
{
if(numberOfPosToRender >= posToRender.length)
posToRender = Arrays.copyOf(posToRender, posToRender.length*2);
posToRender[numberOfPosToRender] = levelPos;
//if(numberOfPosToRender >= posToRender.length)
// posToRender = Arrays.copyOf(posToRender, posToRender.length*2);
posToRender[numberOfPosToRender][0] = detailLevel;
posToRender[numberOfPosToRender][1] = posX;
posToRender[numberOfPosToRender][2] = posZ;
numberOfPosToRender++;
int[] newLevelPos = LevelPosUtil.getRegionModule(LevelPosUtil.convert(levelPos, minDetail));
population[LevelPosUtil.getPosZ(newLevelPos)][LevelPosUtil.getPosZ(newLevelPos)] = (byte) (LevelPosUtil.getDetailLevel(levelPos) + 1);
population[LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel,posX,minDetail))]
[LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel,posZ,minDetail))] = (byte) (detailLevel + 1);
}
public boolean contains(int[] levelPos)
public boolean contains(byte detailLevel, int posX, int posZ)
{
int[] newLevelPos = LevelPosUtil.convert(LevelPosUtil.getRegionModule(levelPos), minDetail);
return (population[LevelPosUtil.getPosZ(newLevelPos)][LevelPosUtil.getPosZ(newLevelPos)] == (LevelPosUtil.getDetailLevel(levelPos) + 1));
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){
this.numberOfPosToRender = 0;
this.regionPosX = regionPosX;
this.regionPosZ = regionPosZ;
if(this.minDetail == minDetail)
{
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - minDetail);
for (int x = 0; x < size; x++)
{
for (int z = 0; z < size; z++)
{
posToRender[0][0] = 0;
posToRender[0][1] = 0;
posToRender[0][2] = 0;
population[x][z] = 0;
}
}
}else{
this.minDetail = minDetail;
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - minDetail);
posToRender = new int[size*size][3];
population = new byte[size][size];
}
}
public int getNumberOfPos()
@@ -42,6 +77,19 @@ public class PosToRenderContainer
return numberOfPosToRender;
}
public byte getNthDetailLevel(int n)
{
return (byte) posToRender[n][0];
}
public int getNthPosX(int n)
{
return posToRender[n][1];
}
public int getNthPosZ(int n)
{
return posToRender[n][2];
}
public int[] getNthPos(int n)
{
return posToRender[n];
@@ -51,6 +99,9 @@ public class PosToRenderContainer
{
StringBuilder builder = new StringBuilder();
builder.append("To render ");
builder.append(numberOfPosToRender);
builder.append('\n');
for(int i = 0; i < numberOfPosToRender; i++)
{
builder.append(posToRender[i][0]);
@@ -41,7 +41,6 @@ import com.seibel.lod.handlers.ReflectionHandler;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.NearFarFogSettings;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.proxy.ClientProxy;
import com.seibel.lod.util.DetailDistanceUtil;
import com.seibel.lod.util.LodUtil;
@@ -127,7 +126,9 @@ public class LodRenderer
/**
* This is used to determine if the LODs should be regenerated
*/
private LevelPos previousPos = new LevelPos((byte) 0, 0, 0);
private byte previousDetailLevel = 0;
private int previousChunkPosX = 0;
private int previousChunkPosZ = 0;
private int prevRenderDistance = 0;
private long prevPlayerPosTime = 0;
private long prevVanillaChunkTime = 0;
@@ -809,7 +810,8 @@ public class LodRenderer
{
DetailDistanceUtil.updateSettings();
fullRegen = true;
previousPos.changeParameters((byte) 4, mc.getPlayer().xChunk, mc.getPlayer().zChunk);
previousChunkPosX = mc.getPlayer().xChunk;
previousChunkPosZ = mc.getPlayer().zChunk;
prevFogDistance = LodConfig.CLIENT.graphics.fogDistance.get();
prevRenderDistance = mc.getRenderDistance();
//should use this when it's ready
@@ -829,12 +831,12 @@ public class LodRenderer
// check if the player has moved
if (newTime - prevPlayerPosTime > LodConfig.CLIENT.buffers.bufferRebuildPlayerMoveTimeout.get())
{
if (previousPos.detailLevel == 0
|| mc.getPlayer().xChunk != previousPos.posX
|| mc.getPlayer().zChunk != previousPos.posZ)
if (mc.getPlayer().xChunk != previousChunkPosX
|| mc.getPlayer().zChunk != previousChunkPosZ)
{
fullRegen = true;
previousPos.changeParameters((byte) 4, mc.getPlayer().xChunk, mc.getPlayer().zChunk);
previousChunkPosX = mc.getPlayer().xChunk;
previousChunkPosZ = mc.getPlayer().zChunk;
//should use this when it's ready
vanillaRenderedChunks = new boolean[renderDistance*2+2][renderDistance*2+2];
}
@@ -21,9 +21,9 @@ import java.awt.Color;
import java.io.File;
import java.util.HashSet;
import com.seibel.lod.objects.DataPoint;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.RegionPos;
import com.seibel.lod.objects.LevelPos.LevelPos;
import com.seibel.lod.wrapper.MinecraftWrapper;
import it.unimi.dsi.fastutil.objects.ObjectList;
@@ -324,13 +324,13 @@ public class LodUtil
{
for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++)
{
LevelPos levelPos = new LevelPos(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
if (!lodDim.doesDataExist(levelPos.clone()))
if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z))
continue;
short[] data = lodDim.getData(levelPos);
short lodAverageHeight = data[0];
long data = lodDim.getData(LodUtil.CHUNK_DETAIL_LEVEL, x, z);
short lodAverageHeight = DataPoint.getHeight(data);
if (playerPos.getY() <= lodAverageHeight)
{
// don't draw Lod's that are taller than the player