diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java index 52392a9d5..08f54d66b 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java @@ -19,6 +19,7 @@ package com.seibel.lod.core.builders.lodBuilding; +import java.util.ConcurrentModificationException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -287,6 +288,10 @@ public class LodBuilder //ApiShared.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}", // chunk.getChunkPosX(), chunk.getChunkPosZ(), chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode); + if (targetLevel != region.getMinDetailLevel()) { + //Concurrency issues happened. + throw new ConcurrentModificationException("Min detail level changed while writing data"); + } region.addChunkOfData(targetLevel, LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, targetLevel), LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkZ, targetLevel), diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferQuad.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferQuad.java index 5273d5971..95724e280 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferQuad.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/BufferQuad.java @@ -31,7 +31,7 @@ import static com.seibel.lod.core.render.LodRenderer.EVENT_LOGGER; * @author ? * @version 4-9-2022 */ -public class BufferQuad +public final class BufferQuad { final short x; final short y; @@ -39,11 +39,12 @@ public class BufferQuad short widthEastWest; /** This is both North/South and Up/Down since the merging logic is the same either way */ short widthNorthSouthOrUpDown; - int color; + final int color; final byte skyLight; final byte blockLight; final LodDirection direction; - + + boolean hasError = false; BufferQuad(short x, short y, short z, short widthEastWest, short widthNorthSouthOrUpDown, int color, byte skylight, byte blocklight, @@ -64,16 +65,13 @@ public class BufferQuad this.blockLight = blocklight; this.direction = direction; } - - - + /** a rough but fast calculation */ double calculateDistance(double relativeX, double relativeY, double relativeZ) { return Math.pow(relativeX - x, 2) + Math.pow(relativeY - y, 2) + Math.pow(relativeZ - z, 2); } - /** compares this quad's position to the given quad */ public int compare(BufferQuad quad, BufferMergeDirectionEnum compareDirection) { @@ -131,6 +129,7 @@ public class BufferQuad */ public boolean tryMerge(BufferQuad quad, BufferMergeDirectionEnum mergeDirection) { + if (quad.hasError || this.hasError) return false; // only merge quads that are in the same direction if (direction != quad.direction) return false; @@ -244,7 +243,8 @@ public class BufferQuad { // these quads are overlapping, they can't be merged EVENT_LOGGER.warn("Overlapping quads detected!"); - quad.color = ColorUtil.rgbToInt(255, 0, 0); + quad.hasError = true; + this.hasError = true; return false; } diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java index 21e77830c..25a2b46ae 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/CubicLodTemplate.java @@ -53,36 +53,54 @@ public class CubicLodTemplate } int color; - if (debugging != DebugMode.OFF && debugging != DebugMode.SHOW_WIREFRAME) - { - if (debugging == DebugMode.SHOW_DETAIL || debugging == DebugMode.SHOW_DETAIL_WIREFRAME) - color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel]; - else /// if (debugging == DebugMode.SHOW_GENMODE || debugging == - /// DebugMode.SHOW_GENMODE_WIREFRAME) - color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[DataPointUtil.getGenerationMode(data)]; - } - else - { - float saturationMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier(); - float brightnessMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier(); - - if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) { - color = DataPointUtil.getColor(data); - } else { - float[] ahsv = ColorUtil.argbToAhsv(DataPointUtil.getColor(data)); - color = ColorUtil.ahsvToArgb(ahsv[0], ahsv[1], ahsv[2] * saturationMultiplier, ahsv[3] * brightnessMultiplier); - //ApiShared.LOGGER.info("Raw color:[{}], AHSV:{}, Out color:[{}]", - // ColorUtil.toString(DataPointUtil.getColor(data)), - // ahsv, ColorUtil.toString(color)); + boolean fullBright = false; + switch (debugging) { + case OFF: + case SHOW_WIREFRAME: + { + float saturationMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier(); + float brightnessMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier(); + if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) { + color = DataPointUtil.getColor(data); + } else { + float[] ahsv = ColorUtil.argbToAhsv(DataPointUtil.getColor(data)); + color = ColorUtil.ahsvToArgb(ahsv[0], ahsv[1], ahsv[2] * saturationMultiplier, ahsv[3] * brightnessMultiplier); + //ApiShared.LOGGER.info("Raw color:[{}], AHSV:{}, Out color:[{}]", + // ColorUtil.toString(DataPointUtil.getColor(data)), + // ahsv, ColorUtil.toString(color)); + } + break; } + case SHOW_DETAIL: + case SHOW_DETAIL_WIREFRAME: + { + color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel]; + fullBright = true; + break; + } + case SHOW_GENMODE: + case SHOW_GENMODE_WIREFRAME: + { + color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[DataPointUtil.getGenerationMode(data)]; + fullBright = true; + break; + } + case SHOW_OVERLAPPING_QUADS: + case SHOW_NON_OVERLAPPING_QUADS_WIREFRAME: + { + color = ColorUtil.WHITE; + fullBright = true; + break; + } + default: + throw new IllegalArgumentException("Unknown debug mode: " + debugging); } - - LodBox.addBoxQuadsToBuilder(quadBuilder, // buffer width, dy, width, // setWidth x, y, z, // setOffset color, // setColor - DataPointUtil.getLightSky(data), DataPointUtil.getLightBlock(data), // setLights + DataPointUtil.getLightSky(data), // setSkyLights + fullBright ? 15 : DataPointUtil.getLightBlock(data), // setBlockLights topData, botData, adjData, adjFillBlack); // setAdjData } } diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java index 410207316..fa1397faa 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java @@ -306,8 +306,11 @@ public class LodQuadBuilder default: throw new IllegalArgumentException("Invalid Axis enum: " + axis); } - putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz), quad.color, - quad.skyLight, quad.blockLight, mx, my, mz); + putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz), + quad.hasError ? ColorUtil.RED : quad.color, + quad.hasError ? 15 : quad.skyLight, + quad.hasError ? 15 : quad.blockLight, + mx, my, mz); } } diff --git a/src/main/java/com/seibel/lod/core/enums/rendering/DebugMode.java b/src/main/java/com/seibel/lod/core/enums/rendering/DebugMode.java index b017a01b1..27867ade4 100644 --- a/src/main/java/com/seibel/lod/core/enums/rendering/DebugMode.java +++ b/src/main/java/com/seibel/lod/core/enums/rendering/DebugMode.java @@ -43,7 +43,13 @@ public enum DebugMode SHOW_GENMODE, /** LOD colors are based on their gen mode, and draws in wireframe. */ - SHOW_GENMODE_WIREFRAME; + SHOW_GENMODE_WIREFRAME, + + /** Only draw overlapping LOD quads. */ + SHOW_OVERLAPPING_QUADS, + + /** Only draw overlapping LOD quads, and draws in wireframe. */ + SHOW_OVERLAPPING_QUADS_WIREFRAME; /** used when cycling through the different modes */ private DebugMode next; @@ -55,7 +61,9 @@ public enum DebugMode SHOW_DETAIL.next = SHOW_DETAIL_WIREFRAME; SHOW_DETAIL_WIREFRAME.next = SHOW_GENMODE; SHOW_GENMODE.next = SHOW_GENMODE_WIREFRAME; - SHOW_GENMODE_WIREFRAME.next = OFF; + SHOW_GENMODE_WIREFRAME.next = SHOW_OVERLAPPING_QUADS; + SHOW_OVERLAPPING_QUADS.next = SHOW_OVERLAPPING_QUADS_WIREFRAME; + SHOW_OVERLAPPING_QUADS_WIREFRAME.next = OFF; } /** returns the next debug mode */ diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java index e791ace2a..435aa1527 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java @@ -294,6 +294,7 @@ public class LodDimension detail = DetailDistanceUtil.getDetailLevelFromDistance(minDistance); if (region.getMinDetailLevel() < detail) { if (region.needSaving) return; // FIXME: A crude attempt at lowering chance of race condition! + if (region.isWriting.get()!=0) return; region.cutTree(detail); region.needSignalToRegenBuffer = true; } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java index 1e9ecfce1..aa08ae2b9 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java @@ -54,7 +54,7 @@ public class LodRegion { private static final byte POSSIBLE_LOD = LodUtil.DETAIL_OPTIONS; /** Holds the lowest (least detailed) detail level in this region */ - private byte minDetailLevel; + private volatile byte minDetailLevel; public byte lastMaxDetailLevel = LodUtil.REGION_DETAIL_LEVEL; /** @@ -161,9 +161,12 @@ public class LodRegion { // detailLevel changes. if (this.dataContainer[detailLevel] == null) return false;// this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel); - if (this.dataContainer[detailLevel].getVerticalSize() != verticalSize) - throw new RuntimeException("Provided data's verticalSize is different from current storage's verticalSize!"); - + if (this.dataContainer[detailLevel].getVerticalSize() != verticalSize) { + throw new RuntimeException( + String.format("Provided data's verticalSize [%d]" + + " is different from current storage's verticalSize [%d] at detail [%d]", + verticalSize, this.dataContainer[detailLevel].getVerticalSize(), detailLevel)); + } boolean updated = this.dataContainer[detailLevel].addChunkOfData(data, posX, posZ, widthX, widthZ, override); //ApiShared.LOGGER.info("addChunkOfData(region:{}, level:{}, x:{}, z:{}, wx:{}, wz:{}, override:{}, updated:{})", // getRegionPos(), detailLevel, posX, posZ, widthX, widthZ, override, updated); @@ -501,7 +504,7 @@ public class LodRegion { - + /** * Updates all children. *
@@ -646,10 +649,10 @@ public class LodRegion { + "only allows adding LevelContainers with a " + "detail level of [" + (minDetailLevel - 1) + "]"); } + dataContainer[levelContainer.getDetailLevel()] = levelContainer; if (levelContainer.getDetailLevel() == minDetailLevel - 1) minDetailLevel = levelContainer.getDetailLevel(); - dataContainer[levelContainer.getDetailLevel()] = levelContainer; needRecheckGenPoint = true; } @@ -662,10 +665,9 @@ public class LodRegion { */ public void cutTree(byte detailLevel) { if (detailLevel > minDetailLevel) { + minDetailLevel = detailLevel; for (byte detailLevelIndex = 0; detailLevelIndex < detailLevel; detailLevelIndex++) dataContainer[detailLevelIndex] = null; - - minDetailLevel = detailLevel; } } diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index dbbdf50ad..14e51eddc 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -250,7 +250,8 @@ public class LodRenderer LagSpikeCatcher drawSetPolygon = new LagSpikeCatcher(); if (CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_DETAIL_WIREFRAME || CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_GENMODE_WIREFRAME - || CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_WIREFRAME) { + || CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_WIREFRAME + || CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_OVERLAPPING_QUADS_WIREFRAME) { GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE); //GL32.glDisable(GL32.GL_CULL_FACE); } diff --git a/src/main/java/com/seibel/lod/core/util/ColorUtil.java b/src/main/java/com/seibel/lod/core/util/ColorUtil.java index 23b309a00..d57cf984f 100644 --- a/src/main/java/com/seibel/lod/core/util/ColorUtil.java +++ b/src/main/java/com/seibel/lod/core/util/ColorUtil.java @@ -38,6 +38,8 @@ public class ColorUtil public static final int BLACK = rgbToInt(0,0,0); public static final int WHITE = rgbToInt(255,255,255); public static final int TRANSPARENT = rgbToInt(0, 0, 0, 0); + + public static final int RED = rgbToInt(255,0,0); private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class); diff --git a/src/main/java/com/seibel/lod/core/util/DetailDistanceUtil.java b/src/main/java/com/seibel/lod/core/util/DetailDistanceUtil.java index 2ee19a9a4..b88bc44d8 100644 --- a/src/main/java/com/seibel/lod/core/util/DetailDistanceUtil.java +++ b/src/main/java/com/seibel/lod/core/util/DetailDistanceUtil.java @@ -104,7 +104,7 @@ public class DetailDistanceUtil public static int getMaxVerticalData(int detail) { - return CONFIG.client().graphics().quality().getVerticalQuality().maxVerticalData[LodUtil.clamp(minDetail, detail, LodUtil.REGION_DETAIL_LEVEL)]; + return CONFIG.client().graphics().quality().getVerticalQuality().maxVerticalData[detail]; } } diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java index a3c459f20..9413ba1a0 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/config/ILodConfigWrapperSingleton.java @@ -842,7 +842,10 @@ public interface ILodConfigWrapperSingleton extends IBindable + " " + DebugMode.SHOW_DETAIL + ": Fake chunks color will be based on their detail level. \n" + " " + DebugMode.SHOW_DETAIL_WIREFRAME + ": Fake chunks color will be based on their detail level, drawn as a wireframe. \n" + " " + DebugMode.SHOW_GENMODE + ": Fake chunks color will be based on their distant generation mode. \n" - + " " + DebugMode.SHOW_GENMODE_WIREFRAME + ": Fake chunks color will be based on their distant generation mode, drawn as a wireframe. \n"; + + " " + DebugMode.SHOW_GENMODE_WIREFRAME + ": Fake chunks color will be based on their distant generation mode, drawn as a wireframe. \n" + + " " + DebugMode.SHOW_OVERLAPPING_QUADS + ": Fake chunks will be drawn with total white, but overlapping quads will be drawn with red. \n" + + " " + DebugMode.SHOW_OVERLAPPING_QUADS_WIREFRAME + ": Fake chunks will be drawn with total white, \n" + + " but overlapping quads will be drawn with red, drawn as a wireframe. \n"; DebugMode getDebugMode(); void setDebugMode(DebugMode newDebugMode);