From a4546c63e3fbeee05d2789aee45e6f90a95eb1a7 Mon Sep 17 00:00:00 2001 From: TomTheFurry Date: Tue, 26 Jul 2022 17:06:50 +0800 Subject: [PATCH] Fix bunches of bugs. Quad tree ticks! Gen call is fired! Chunk gen works! Next to fix: File updates --- .../a7/datatype/transform/LodDataBuilder.java | 8 +- .../core/a7/generation/GenerationQueue.java | 23 ++- .../com/seibel/lod/core/a7/pos/DhLodPos.java | 2 +- .../seibel/lod/core/a7/pos/DhSectionPos.java | 13 +- .../lod/core/a7/render/LodQuadTree.java | 137 ++++++++++++------ .../lod/core/a7/render/LodRenderSection.java | 5 + .../core/a7/render/RenderBufferHandler.java | 5 +- .../a7/save/io/render/RenderMetaFile.java | 2 + .../com/seibel/lod/core/util/EventLoop.java | 12 +- .../com/seibel/lod/core/util/LodUtil.java | 32 +++- .../util/gridList/MovableGridRingList.java | 4 +- .../wrapperInterfaces/IWrapperFactory.java | 1 + .../block/IBlockStateWrapper.java | 2 - 13 files changed, 168 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/transform/LodDataBuilder.java b/src/main/java/com/seibel/lod/core/a7/datatype/transform/LodDataBuilder.java index 8ebb5cdb4..6daee1dc6 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/transform/LodDataBuilder.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/transform/LodDataBuilder.java @@ -2,12 +2,15 @@ package com.seibel.lod.core.a7.datatype.transform; import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; import com.seibel.lod.core.a7.datatype.full.FullFormat; +import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; +import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper; import it.unimi.dsi.fastutil.longs.LongArrayList; public class LodDataBuilder { + private static final IBlockStateWrapper AIR = SingletonInjector.INSTANCE.get(IWrapperFactory.class).getAirBlockStateWrapper(); public static ChunkSizedData createChunkData(IChunkWrapper chunk) { if (!canGenerateLodFromChunk(chunk)) return null; @@ -18,7 +21,7 @@ public class LodDataBuilder { LongArrayList longs = new LongArrayList(chunk.getHeight()/4); int lastY = chunk.getMaxBuildHeight(); IBiomeWrapper biome = chunk.getBiome(x, lastY, z); - IBlockStateWrapper blockState = IBlockStateWrapper.AIR; + IBlockStateWrapper blockState = AIR; int mappedId = chunkData.getMapping().setAndGetId(biome, blockState); byte light = (byte) (chunk.getBlockLight(x,lastY,z) << 4 + chunk.getSkyLight(x,lastY,z)); int y=chunk.getMaxY(x, z); @@ -42,7 +45,8 @@ public class LodDataBuilder { } } longs.add(FullFormat.encode(mappedId, lastY-y+1, y+1, light)); - chunkData.setSingleColumn(longs.toArray((long[]) null), x, z); + + chunkData.setSingleColumn(longs.toArray(new long[0]), x, z); } } diff --git a/src/main/java/com/seibel/lod/core/a7/generation/GenerationQueue.java b/src/main/java/com/seibel/lod/core/a7/generation/GenerationQueue.java index 52768a04b..4172ba7b0 100644 --- a/src/main/java/com/seibel/lod/core/a7/generation/GenerationQueue.java +++ b/src/main/java/com/seibel/lod/core/a7/generation/GenerationQueue.java @@ -16,6 +16,7 @@ import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.LinkedList; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.function.BiConsumer; public class GenerationQueue implements PlaceHolderQueue { @@ -29,7 +30,7 @@ public class GenerationQueue implements PlaceHolderQueue { } public void track(PlaceHolderRenderSource source) { - logger.info("Tracking source {} at {}", source, source.getSectionPos()); + //logger.info("Tracking source {} at {}", source, source.getSectionPos()); trackers.put(source.getSectionPos(), new WeakReference<>(source)); } @@ -108,25 +109,31 @@ public class GenerationQueue implements PlaceHolderQueue { assert count > 0; assert granularity >= 4; // Thanks compiler. Guess having a 'always true' warning means I did it right. logger.info("Generating section {} of size {} with granularity {} at {}", pos, count, granularity, chunkPosMin); - +//FIXME: Handle size != 1 case CompletableFuture> dataFuture = generator.generate(chunkPosMin, granularity); dataFuture.whenComplete((data, ex) -> { if (ex != null) { - logger.error("Error generating data for section " + pos + ": " + ex); + if (ex instanceof CompletionException) { + ex = ex.getCause(); + } + logger.error("Error generating data for section {}", pos, ex); return; } assert data != null; - if (data.gridSize != count) { - logger.error("Generated data grid size (" + data.gridSize - + ") does not match expected size (" + count + ") for section " + pos); - return; - } + if (data.gridSize < (1 << (granularity-4))) + throw new IllegalStateException("Generator returned chunks of size " + + data.gridSize + " but requested granularity was " + granularity + + " (equals to chunks of : " + (1 << (granularity-4)) + ") @ " + chunkPosMin); + final byte sectionDetail = (byte) (dataDetail + FullDataSource.SECTION_SIZE_OFFSET); data.forEachPos((x,z) -> { ChunkSizedData chunkData = data.get(x,z); DhLodPos chunkDataPos = new DhLodPos((byte) (dataDetail + 4), x, z).convertUpwardsTo(sectionDetail); DhSectionPos sectionPos = new DhSectionPos(chunkDataPos.detail, chunkDataPos.x, chunkDataPos.z); + logger.info("Writing chunk {} with data detail {} to section {}", + new DHChunkPos(x+chunkPosMin.x,z+chunkPosMin.z), + dataDetail, sectionPos); write(sectionPos, chunkData); }); }); diff --git a/src/main/java/com/seibel/lod/core/a7/pos/DhLodPos.java b/src/main/java/com/seibel/lod/core/a7/pos/DhLodPos.java index b4c79abbc..b9463acf8 100644 --- a/src/main/java/com/seibel/lod/core/a7/pos/DhLodPos.java +++ b/src/main/java/com/seibel/lod/core/a7/pos/DhLodPos.java @@ -16,7 +16,7 @@ public class DhLodPos { } public String toString() { - return "DhLodPos(" + detail + ", " + x + ", " + z + ")"; + return "[" + detail + "*" + x + "," + z + "]"; } public DhLodUnit getX() { diff --git a/src/main/java/com/seibel/lod/core/a7/pos/DhSectionPos.java b/src/main/java/com/seibel/lod/core/a7/pos/DhSectionPos.java index a8b1295a8..ff01439cc 100644 --- a/src/main/java/com/seibel/lod/core/a7/pos/DhSectionPos.java +++ b/src/main/java/com/seibel/lod/core/a7/pos/DhSectionPos.java @@ -35,7 +35,7 @@ public class DhSectionPos { return new DhLodUnit(sectionDetail, 1 << offset); } public DhLodPos getCenter() { - return getCenter((byte) (sectionDetail-1)); + return getCenter((byte)0); } public DhLodPos getCorner() { return getCorner((byte) (sectionDetail-1)); @@ -49,7 +49,7 @@ public class DhSectionPos { if (sectionDetail <= 0) throw new IllegalStateException("section detail must be greater than 0"); return new DhSectionPos((byte) (sectionDetail - 1), sectionX * 2 + (child0to3 & 1), - sectionZ * 2 + (child0to3 & 2) / 2); + sectionZ * 2 + ((child0to3 & 2) >> 1)); } public void forEachChild(Consumer callback){ @@ -59,7 +59,7 @@ public class DhSectionPos { } public DhSectionPos getParent(){ - return new DhSectionPos((byte) (sectionDetail + 1), sectionX / 2, sectionZ / 2); + return new DhSectionPos((byte) (sectionDetail + 1), sectionX >> 1, sectionZ >> 1); } public DhSectionPos getAdjacent(ELodDirection dir) { @@ -79,10 +79,9 @@ public class DhSectionPos { @Override public String toString() { - return "DhSectionPos{" + - "sectionDetail=" + sectionDetail + - ", sectionX=" + sectionX + - ", sectionZ=" + sectionZ + + return "{" + sectionDetail + + "*" + sectionX + + "," + sectionZ + '}'; } diff --git a/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java b/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java index 99b322d5b..b1da1d602 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/core/a7/render/LodQuadTree.java @@ -1,5 +1,6 @@ package com.seibel.lod.core.a7.render; +import com.seibel.lod.core.a7.datatype.LodRenderSource; import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource; import com.seibel.lod.core.a7.level.IClientLevel; import com.seibel.lod.core.a7.pos.DhBlockPos2D; @@ -30,6 +31,7 @@ public class LodQuadTree { * by implementing different abstract methods */ private static final byte LAYER_BEGINNING_OFFSET = ColumnRenderSource.SECTION_SIZE_OFFSET; + private static final boolean SUPER_VERBOSE_LOGGING = false; public final byte getLayerDataDetailOffset(byte sectionDetail) { return ColumnRenderSource.SECTION_SIZE_OFFSET; } @@ -59,6 +61,7 @@ public class LodQuadTree { * @param initialPlayerZ player z coordinate */ public LodQuadTree(IClientLevel level, int viewDistance, int initialPlayerX, int initialPlayerZ, IRenderSourceProvider provider) { + DetailDistanceUtil.updateSettings(); //TODO: Move this to somewhere else this.level = level; renderSourceProvider = provider; this.viewDistance = viewDistance; @@ -71,13 +74,22 @@ public class LodQuadTree { } { // Construct the ringLists + LOGGER.info("Creating ringLists with player center at {}", new Pos2D(initialPlayerX, initialPlayerZ)); for (byte i = LAYER_BEGINNING_OFFSET; i < numbersOfSectionLevels; i++) { byte targetDataDetail = getLayerDataDetail(i); int maxDist = getFurthestDistance(targetDataDetail); - int halfSize = LodUtil.ceilDiv(maxDist, (1 << i)) + 1; - LOGGER.info("Creating ringList {} with size {}", i, halfSize*2+1); + int halfSize = LodUtil.ceilDiv(maxDist, (1 << i)) + 2; // +2 to make sure the section is fully contained in the ringList + { + DhSectionPos checkerPos = new DhSectionPos(i, halfSize, halfSize); + byte checkedDetail = calculateExpectedDetailLevel(new DhBlockPos2D(initialPlayerX, initialPlayerZ),checkerPos); + LodUtil.assertTrue(checkedDetail > targetDataDetail, + "in {}, getFuthestDistance return {} which would be contained in range {}, but calculateExpectedDetailLevel at {} is {} <= {}", + i, maxDist, halfSize - 2, checkerPos, checkedDetail, targetDataDetail); + } + LOGGER.info("ringlist centered in {} with halfSize {} (maxDist {}, dataDetail {})", new Pos2D(initialPlayerX >> i, initialPlayerZ >> i), halfSize, maxDist, targetDataDetail); ringLists[i - LAYER_BEGINNING_OFFSET] = new MovableGridRingList<>(halfSize, initialPlayerX >> i, initialPlayerZ >> i); + LOGGER.info("Creating ringList {}: {}", i, ringLists[i - LAYER_BEGINNING_OFFSET].toString()); } } } @@ -159,7 +171,8 @@ public class LodQuadTree { * @return the furthest distance to the center, in blocks */ public int getFurthestDistance(byte detailLevel) { - return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel)); + return (int)Math.ceil(DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel + 1)); + // +1 because that's the border to the next detail level, and we want to include up to it. } /** @@ -181,7 +194,28 @@ public class LodQuadTree { public LodRenderSection getChildSection(DhSectionPos pos, int child0to3) { return getSection(pos.getChild(child0to3)); } - + + private LodRenderSection _set(MovableGridRingList list, int x, int z, LodRenderSection t) { + LodUtil.assertTrue(t != null, "setting null at [{},{}] in {}", x, z, list.toString()); + LodUtil.assertTrue(t.pos.sectionX == x && t.pos.sectionZ == z, "pos {} != [{},{}] in {}", t.pos, x, z, list.toString()); + LodRenderSection s = list.setChained(x,z,t); + LodUtil.assertTrue(s != null, "returned null at [{},{}]: {}", x, z, list.toString()); + LodUtil.assertTrue(s == t,"{} != {} in {}",s,t, list.toString()); + return s; + } + private LodRenderSection _getNotNull(MovableGridRingList list, int x, int z) { + LodUtil.assertTrue(list.inRange(x,z), "[{},{}] not in range of {}", x, z, list.toString()); + LodRenderSection s = list.get(x,z); + LodUtil.assertTrue(s != null, "getting null at [{},{}] in {}", x, z, list.toString()); + LodUtil.assertTrue(s.pos.sectionX == x && s.pos.sectionZ == z, "obj {} != [{},{}] in {}", s, x, z, list.toString()); + return s; + } + private LodRenderSection _get(MovableGridRingList list, int x, int z) { + LodRenderSection s = list.get(x,z); + LodUtil.assertTrue(s == null || (s.pos.sectionX == x && s.pos.sectionZ == z), "obj {} != [{},{}] in {}", s, x, z, list.toString()); + return s; + } + /** * This function update the quadTree based on the playerPos and the current game configs (static and global) * @param playerPos the reference position for the player @@ -207,7 +241,7 @@ public class LodQuadTree { // - set childCount to 0 // If section != null && child != 0: //TODO: Should I move this createChild steps to Second tick pass? // - // Section will be in the unloaded state. - // - create parent if it doesn't exist, with childCount = 1 + // - create parent if not at final level and if it doesn't exist, with childCount = 1 // - for each child: // - if null, create new with childCount = 0 (force load due to neighboring issues) // - else if childCount == -1, set childCount = 0 (rescue it) @@ -241,71 +275,77 @@ public class LodQuadTree { ringList.forEachPosOrdered((section, pos) -> { if (f_sectLevel == LAYER_BEGINNING_OFFSET && section != null) { section.childCount = 0; + //LOGGER.info("sect {} in first layer with non-null. Reset childCount", section.pos); } if (section != null && section.childCount != 0) { // Section will be in the unloaded state. - LodUtil.assertTrue(parentRingList != null); - LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); - if (parent == null) { - parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1, - new LodRenderSection(section.pos.getParent())); - LodUtil.assertTrue(parent != null, "tried to set section at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList); - parent.childCount++; + if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} has child", section.pos); + if (parentRingList != null) { + LodRenderSection parent = _get(parentRingList, pos.x >> 1, pos.y >> 1); + if (parent == null) { + if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing parent. Creating at {}", section.pos, section.pos.getParent()); + parent = _set(parentRingList, pos.x >> 1, pos.y >> 1, new LodRenderSection(section.pos.getParent())); + parent.childCount++; + if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} childs.", section.pos.getParent(), parent.childCount); + } + LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0); } - LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0); for (byte i = 0; i < 4; i++) { DhSectionPos childPos = section.pos.getChild(i); LodUtil.assertTrue(childRingList != null); - LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ); + LodRenderSection child = _get(childRingList, childPos.sectionX, childPos.sectionZ); if (child == null) { - child = childRingList.setChained(childPos.sectionX, childPos.sectionZ, - new LodRenderSection(childPos)); - LodUtil.assertTrue(child != null, "tried to set section at " + childPos.sectionX + "," + childPos.sectionZ + ", list is " + childRingList); + if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing child at {}. Creating.", section.pos, childPos); + child = _set(childRingList, childPos.sectionX, childPos.sectionZ, new LodRenderSection(childPos)); child.childCount = 0; } else if (child.childCount == -1) { + if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} rescued child at {}.", section.pos, childPos); child.childCount = 0; } } section.childCount = 4; } else { - DhSectionPos sectPos = section != null ? section.pos : new DhSectionPos(f_sectLevel, pos.x, pos.y); + final DhSectionPos sectPos = section != null ? section.pos : new DhSectionPos(f_sectLevel, pos.x, pos.y); LodUtil.assertTrue(sectPos.sectionDetail == f_sectLevel && sectPos.sectionX == pos.x && sectPos.sectionZ == pos.y, - "sectPos: " + sectPos + ", pos: " + pos + ", sectLevel: " + f_sectLevel); + "sectPos {} != {} @ {}", sectPos, pos, f_sectLevel); byte targetLevel = calculateExpectedDetailLevel(playerPos, sectPos); + if (SUPER_VERBOSE_LOGGING) LOGGER.info("0 child sect {}(null?{}) - target:{}/{} (parent:{})", sectPos, section == null, + targetLevel, getLayerDataDetail(f_sectLevel), + f_sectLevel == numbersOfSectionLevels-1 ? "N/A" : getLayerDataDetail((byte) (f_sectLevel+1))); if (f_sectLevel == numbersOfSectionLevels -1) { // Section is in the top level. if (targetLevel > getLayerDataDetail(f_sectLevel) && section != null) { + if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} in top & target>current. Mark as free.", sectPos); section.childCount = -1; } if (targetLevel <= getLayerDataDetail(f_sectLevel) && section == null) { - section = ringList.setChained(pos.x, pos.y, - new LodRenderSection(sectPos)); - LodUtil.assertTrue(section != null, "tried to set section at " + pos.x + "," + pos.y +", list is " + ringList); + if (SUPER_VERBOSE_LOGGING) LOGGER.info("null sect {} in top & target<=current. Creating.", sectPos); + section = _set(ringList, pos.x, pos.y, new LodRenderSection(sectPos)); } } else { // Section is not the top level. So we also need to consider the parent. if (targetLevel >= getLayerDataDetail((byte) (f_sectLevel+1)) && section != null) { + if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} target>=nextLevel. Mark as free.", sectPos); LodUtil.assertTrue(parentRingList != null); - LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); - LodUtil.assertTrue(parent != null, "fail to get parent setion at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList); + LodRenderSection parent = _getNotNull(parentRingList, pos.x >> 1, pos.y >> 1); LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0); parent.childCount--; + if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} child.", sectPos, parent.childCount); section.childCount = -1; } if (targetLevel < getLayerDataDetail((byte) (f_sectLevel+1)) && section == null) { - section = ringList.setChained(pos.x, pos.y, - new LodRenderSection(sectPos)); - LodUtil.assertTrue(section != null, "tried to set section at " + pos.x + "," + pos.y +", list is " + ringList); + if (SUPER_VERBOSE_LOGGING) LOGGER.info("null sect {} target> 1, pos.y >> 1); + LodRenderSection parent = _get(parentRingList, pos.x >> 1, pos.y >> 1); if (parent == null) { - parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1, - new LodRenderSection(sectPos.getParent())); - LodUtil.assertTrue(parent != null, "tried to set section at " + (pos.x >> 1) + "," + (pos.y >> 1) +", list is " + parentRingList); + if (SUPER_VERBOSE_LOGGING) LOGGER.info("sect {} missing parent. Creating at {}", sectPos, sectPos.getParent()); + parent = _set(parentRingList, pos.x >> 1, pos.y >> 1, new LodRenderSection(sectPos.getParent())); } parent.childCount++; + if (SUPER_VERBOSE_LOGGING) LOGGER.info("parent sect {} now has {} childs.", sectPos.getParent(), parent.childCount); } } } @@ -362,21 +402,6 @@ public class LodQuadTree { section.childCount = 4; } - // Assertion steps - LodUtil.assertTrue(section.childCount == 4 || section.childCount == 0 || section.childCount == -1); - if (section.childCount == 4) LodUtil.assertTrue( - getChildSection(section.pos, 0) != null && - getChildSection(section.pos, 1) != null && - getChildSection(section.pos, 2) != null && - getChildSection(section.pos, 3) != null); - if (section.childCount == 0) LodUtil.assertTrue( - getChildSection(section.pos, 0) == null && - getChildSection(section.pos, 1) == null && - getChildSection(section.pos, 2) == null && - getChildSection(section.pos, 3) == null); - if (section.childCount == -1) LodUtil.assertTrue( - getParentSection(section.pos).childCount == 0); - // Call load on new sections, and tick on existing ones, and dispose old sections if (section.childCount == -1) { ringList.set(pos.x, pos.y, null); @@ -387,10 +412,26 @@ public class LodQuadTree { } else if (section.isOutdated()) { section.reload(renderSourceProvider); } - if (section.childCount == 4) section.enableRender(level, this); - if (section.childCount == 0) section.disableRender(); + if (section.childCount == 4) section.disableRender(); + if (section.childCount == 0) section.enableRender(level, this); section.tick(this); } + + // Assertion steps + LodUtil.assertTrue(section.childCount == 4 || section.childCount == 0 || section.childCount == -1); + if (section.pos.sectionDetail == LAYER_BEGINNING_OFFSET) LodUtil.assertTrue(section.childCount == 0); + if (section.childCount == 4) LodUtil.assertTrue( + getChildSection(section.pos, 0) != null && + getChildSection(section.pos, 1) != null && + getChildSection(section.pos, 2) != null && + getChildSection(section.pos, 3) != null); + if (section.childCount == 0 && section.pos.sectionDetail > LAYER_BEGINNING_OFFSET) LodUtil.assertTrue( + getChildSection(section.pos, 0) == null && + getChildSection(section.pos, 1) == null && + getChildSection(section.pos, 2) == null && + getChildSection(section.pos, 3) == null); + if (section.childCount == -1 && section.pos.sectionDetail < numbersOfSectionLevels-1) LodUtil.assertTrue( + getParentSection(section.pos).childCount == 0); }); } } diff --git a/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java index cf2f5b1c1..a15fccb02 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java +++ b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java @@ -81,6 +81,11 @@ public class LodRenderSection { return lodRenderSource != null; } + //FIXME: Used by RenderBufferHandler + public int FIXME_BYPASS_DONT_USE_getChildCount() { + return childCount; + } + public boolean isLoading() { return loadFuture != null; } diff --git a/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java b/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java index fe2f1ed00..df58b7fd3 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java +++ b/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java @@ -17,7 +17,7 @@ public class RenderBufferHandler { class RenderBufferNode implements AutoCloseable { public final DhSectionPos pos; public volatile RenderBufferNode[] children = null; - public AtomicReference renderBufferSlot = null; + public final AtomicReference renderBufferSlot = new AtomicReference<>(); public RenderBufferNode(DhSectionPos pos) { this.pos = pos; @@ -63,7 +63,8 @@ public class RenderBufferHandler { // Update children's render buffer state // TODO: Improve this! (Checking section.isLoaded() as if its not loaded, it can only be because // it has children. (But this logic is... really hard to read!) - boolean shouldHaveChildren = !section.isLoaded(); + // FIXME: Above comment is COMPLETELY WRONG! I am an idiot! + boolean shouldHaveChildren = section.FIXME_BYPASS_DONT_USE_getChildCount() > 0; if (shouldHaveChildren) { if (children == null) { RenderBufferNode[] childs = new RenderBufferNode[4]; diff --git a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java index 18fad619a..dfc741181 100644 --- a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java +++ b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java @@ -37,11 +37,13 @@ public class RenderMetaFile extends MetaFile { // Not sure if it will cause issues or not. public void updateChunkIfNeeded(ChunkSizedData chunkData) { CompletableFuture source = _readCached(data.get()); + if (source == null) return; if (source.isDone()) source.join().update(chunkData); } public CompletableFuture flushAndSave(ExecutorService renderCacheThread) { CompletableFuture source = _readCached(data.get()); + if (source == null) return CompletableFuture.completedFuture(null); return source.thenAccept((a)->{}); //TODO: Should we save the data or let user re-calculate it on new load? } diff --git a/src/main/java/com/seibel/lod/core/util/EventLoop.java b/src/main/java/com/seibel/lod/core/util/EventLoop.java index ba0c5e129..6a56b445d 100644 --- a/src/main/java/com/seibel/lod/core/util/EventLoop.java +++ b/src/main/java/com/seibel/lod/core/util/EventLoop.java @@ -1,16 +1,20 @@ package com.seibel.lod.core.util; +import com.seibel.lod.core.ModInfo; import com.seibel.lod.core.logging.DhLoggerBuilder; import org.apache.logging.log4j.Logger; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutorService; public class EventLoop { //FIXME This should have close. We are leaking stuff. + private final boolean PAUSE_ON_ERROR = ModInfo.IS_DEV_BUILD; private final Logger logger = DhLoggerBuilder.getLogger(); private final ExecutorService executorService; private final Runnable runnable; private CompletableFuture future; + private boolean isRunning = true; public EventLoop(ExecutorService executorService, Runnable runnable) { this.executorService = executorService; this.runnable = runnable; @@ -19,11 +23,15 @@ public class EventLoop { //FIXME This should have close. We are leaking stuff. if (future != null && future.isDone()) { try { future.join(); + } catch (CompletionException ce) { + logger.error("Uncaught exception in event loop", ce.getCause()); + if (PAUSE_ON_ERROR) isRunning = false; } catch (Exception e) { - logger.error("Uncaught exception in event loop", e); + logger.error("Exception in event loop", e); + if (PAUSE_ON_ERROR) isRunning = false; } finally {future = null;} } - if (future == null) { + if (future == null && isRunning) { future = CompletableFuture.runAsync(runnable, executorService); } } diff --git a/src/main/java/com/seibel/lod/core/util/LodUtil.java b/src/main/java/com/seibel/lod/core/util/LodUtil.java index a73cbe72f..638c9826d 100644 --- a/src/main/java/com/seibel/lod/core/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/core/util/LodUtil.java @@ -28,6 +28,7 @@ import com.seibel.lod.core.config.Config; import com.seibel.lod.core.enums.config.EServerFolderNameMode; import com.seibel.lod.core.enums.config.EVanillaOverdraw; import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; +import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.objects.ParsedIp; import com.seibel.lod.core.objects.Pos2D; @@ -39,6 +40,9 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper; import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.message.Message; /** * This class holds methods and constants that may be used in multiple places. @@ -50,6 +54,7 @@ public class LodUtil { private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); /** * Vanilla render distances less than or equal to this will not allow partial @@ -419,7 +424,20 @@ public class LodUtil public static void checkInterruptsUnchecked() { if (Thread.interrupted()) throw new RuntimeException(new InterruptedException()); } - + + /** + * Format a given string with params using log4j's MessageFormat + * + * @apiNote This 'format' SHOULD ONLY be used for logging and debugging purposes! + * Do not use it for deserialization or naming of objects. + * @param str The string to format + * @param param The parameters to use in the string + * @return A message object. Call .toString() to get the string. + * @author leetom + */ + public static String formatLog(String str, Object... param) { + return LOGGER.getMessageFactory().newMessage(str, param).getFormattedMessage(); + } /** * Returns a shortened version of the given string that is no longer than maxLength.
@@ -441,14 +459,20 @@ public class LodUtil if (!condition) throw new RuntimeException("Assertion failed"); } public static void assertTrue(boolean condition, String message) { - if (!condition) throw new RuntimeException("Assertion failed: " + message); + if (!condition) throw new RuntimeException("Assertion failed:\n " + message); } - public static void assertNotReach(String message) { - throw new RuntimeException("Assert Not Reach failed: " + message); + public static void assertTrue(boolean condition, String message, Object... args) { + if (!condition) throw new RuntimeException("Assertion failed:\n " + formatLog(message, args)); } public static void assertNotReach() { throw new RuntimeException("Assert Not Reach failed"); } + public static void assertNotReach(String message) { + throw new RuntimeException("Assert Not Reach failed:\n " + message); + } + public static void assertNotReach(String message, Object... args) { + throw new RuntimeException("Assert Not Reach failed:\n " + formatLog(message, args)); + } public static ExecutorService makeSingleThreadPool(String name, int relativePriority) { return Executors.newSingleThreadExecutor(new LodThreadFactory(name, Thread.NORM_PRIORITY+relativePriority)); } diff --git a/src/main/java/com/seibel/lod/core/util/gridList/MovableGridRingList.java b/src/main/java/com/seibel/lod/core/util/gridList/MovableGridRingList.java index f8e900c88..6f6f376d4 100644 --- a/src/main/java/com/seibel/lod/core/util/gridList/MovableGridRingList.java +++ b/src/main/java/com/seibel/lod/core/util/gridList/MovableGridRingList.java @@ -33,7 +33,7 @@ import java.util.function.Consumer; public class MovableGridRingList extends ArrayList implements List { - private AtomicReference pos = new AtomicReference(); + private final AtomicReference pos = new AtomicReference<>(); private final int halfSize; private final int size; @@ -329,7 +329,7 @@ public class MovableGridRingList extends ArrayList implements List { @Override public String toString() { Pos2D p = pos.get(); - return "MovabeGridRingList[" + p.x+halfSize + "," + p.y+halfSize + "] " + size + "*" + size + "[" + size() + "]"; + return "MovabeGridRingList[" + (p.x+halfSize) + "," + (p.y+halfSize) + "] " + size + "*" + size + "[" + size() + "]"; } public String toDetailString() { diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/IWrapperFactory.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/IWrapperFactory.java index c825f2488..c08e8f357 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/IWrapperFactory.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/IWrapperFactory.java @@ -36,4 +36,5 @@ public interface IWrapperFactory extends IBindable AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(ILevel targetLevel); IBiomeWrapper deserializeBiomeWrapper(String str); IBlockStateWrapper deserializeBlockStateWrapper(String str); + IBlockStateWrapper getAirBlockStateWrapper(); } diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/IBlockStateWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/IBlockStateWrapper.java index 005f763b8..7f9719565 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/IBlockStateWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/block/IBlockStateWrapper.java @@ -1,7 +1,5 @@ package com.seibel.lod.core.wrapperInterfaces.block; public interface IBlockStateWrapper { - IBlockStateWrapper AIR = null; - String serialize(); }