diff --git a/src/main/java/com/seibel/lod/core/a7/Initializer.java b/src/main/java/com/seibel/lod/core/a7/Initializer.java index 4cc02a15f..5fe3ed35d 100644 --- a/src/main/java/com/seibel/lod/core/a7/Initializer.java +++ b/src/main/java/com/seibel/lod/core/a7/Initializer.java @@ -1,13 +1,9 @@ package com.seibel.lod.core.a7; import com.seibel.lod.core.a7.datatype.column.ColumnRenderLoader; -import com.seibel.lod.core.a7.render.LodQuadTree; public class Initializer { public static void init() { - ColumnRenderLoader columnRenderLoader = new ColumnRenderLoader(); - LodQuadTree.registerLayerLoader(columnRenderLoader, (byte) 7); // 7 or above - - + ColumnRenderLoader unused = new ColumnRenderLoader(); // Auto register into the loader system } } diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/EmptyRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/EmptyRenderSource.java index 8ddca6cad..3a85e79bd 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/EmptyRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/EmptyRenderSource.java @@ -47,7 +47,11 @@ public class EmptyRenderSource implements LodRenderSource { } @Override - public void update(DHChunkPos chunkPos, ChunkSizedData chunkData) { + public void update(ChunkSizedData chunkData) { + } + @Override + public byte getRenderVersion() { + return 0; } } diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java index ba8a3a9b3..deb5d8234 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java @@ -10,11 +10,10 @@ import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.render.RenderBuffer; import com.seibel.lod.core.a7.save.io.render.RenderMetaFile; import com.seibel.lod.core.enums.ELodDirection; -import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.objects.LodDataView; import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.render.LodQuadTree; -import com.seibel.lod.core.a7.render.LodSection; +import com.seibel.lod.core.a7.render.LodRenderSection; import com.seibel.lod.core.a7.datatype.LodRenderSource; import java.io.DataInputStream; @@ -256,7 +255,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { if (inBuildRenderBuffer == null) { ColumnRenderSource[] data = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length]; for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) { - LodSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels + LodRenderSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels if (section.getRenderContainer() != null && section.getRenderContainer() instanceof ColumnRenderBuffer) { data[direction.ordinal()-2] = ((ColumnRenderSource) section.getRenderContainer()); } diff --git a/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java b/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java index fadc156c7..3198e80f6 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java @@ -30,7 +30,7 @@ public class DhClientLevel implements IClientLevel { public DhClientLevel(ClientOnlySaveStructure save, ILevelWrapper level) { this.save = save; dataFileHandler = new RemoteDataFileHandler(); - renderFileHandler = new RenderFileHandler(dataFileHandler, save.getRenderCacheFolder(level)); + renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level)); tree = new LodQuadTree(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16, MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler); renderBufferHandler = new RenderBufferHandler(tree); @@ -38,16 +38,17 @@ public class DhClientLevel implements IClientLevel { FileScanner.scanFile(save, level, dataFileHandler, renderFileHandler); } - public void tick() { - tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos())); - renderBufferHandler.update(); - } - @Override public void dumpRamUsage() { //TODO } + @Override + public void clientTick() { + tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos())); + renderBufferHandler.update(); + } + @Override public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler) { if (renderer == null) { diff --git a/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java b/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java index 0c171f043..b92d99d73 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java @@ -31,7 +31,7 @@ public class DhClientServerLevel implements IClientLevel, IServerLevel { this.level = level; this.save = save; dataFileHandler = new LocalDataFileHandler(this, save.getDataFolder(level)); - renderFileHandler = new RenderFileHandler(dataFileHandler, save.getRenderCacheFolder(level)); + renderFileHandler = new RenderFileHandler(dataFileHandler, this, save.getRenderCacheFolder(level)); tree = new LodQuadTree(Config.Client.Graphics.Quality.lodChunkRenderDistance.get()*16, MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, renderFileHandler); renderBufferHandler = new RenderBufferHandler(tree); 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 30e2828e7..7639c83a6 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,6 +1,6 @@ package com.seibel.lod.core.a7.render; -import com.seibel.lod.core.a7.datatype.RenderSourceLoader; +import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource; import com.seibel.lod.core.a7.pos.DhBlockPos2D; import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider; @@ -10,8 +10,6 @@ import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.gridList.MovableGridRingList; import org.apache.logging.log4j.Logger; -import java.util.ArrayList; - // QuadTree built from several layers of 2d ring buffers /** @@ -29,71 +27,24 @@ public class LodQuadTree { * Note: all config value should be via the class that extends this class, and * by implementing different abstract methods */ - + private static final byte LAYER_BEGINNING_OFFSET = ColumnRenderSource.SECTION_SIZE_OFFSET; + public final byte getLayerDataDetailOffset(byte sectionDetail) { + return ColumnRenderSource.SECTION_SIZE_OFFSET; + } + public final byte getLayerSectionDetailOffset(byte dataDetail) { + return ColumnRenderSource.SECTION_SIZE_OFFSET; + } + public final byte getLayerDataDetail(byte sectionDetail) { + return (byte) (sectionDetail - getLayerDataDetailOffset(sectionDetail)); + } + public final byte getLayerSectionDetail(byte dataDetail) { + return (byte) (dataDetail + getLayerSectionDetailOffset(dataDetail)); + } + + private static final Logger LOGGER = DhLoggerBuilder.getLogger("LodQuadTree"); + public final byte numbersOfSectionLevels; - public final byte startingSectionLevel; - private final MovableGridRingList[] ringLists; - - static final ArrayList layerLoaderConfig = new ArrayList<>(); - - static final Logger LOGGER = DhLoggerBuilder.getLogger("LodQuadTree"); - - public static void registerLayerLoader(RenderSourceLoader loader, byte sectionLevel) { - LOGGER.info("Registering loader for section level " + sectionLevel + " for " + loader.getClass().getSimpleName()); - while (layerLoaderConfig.size() <= sectionLevel) { - layerLoaderConfig.add(null); - } - if (layerLoaderConfig.set(sectionLevel, loader) != null) { - throw new RuntimeException("Layer loader for level " + sectionLevel + " has a registry conflict!"); - } - } - -// static { -// Collections.addAll(layerLoaderConfig, -// null, -// null, //1 -// null, //2 -// null, //3 -// new ContainerTypeConfigEntry(FullDatatype.class, (byte) 4), //4 -> 0 -// null, //5 force breaks down to 4 -> 0 -// null, //6 force breaks down to 4 -> 0 -// new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET), //7 -> 1 -// new ContainerTypeConfigEntry(ColumnDatatype.class, ColumnDatatype.SECTION_SIZE_OFFSET) //8 -> 2 -// // ... And same onwards -// ); -// } - - static class SectionDetailLayer { - final byte targetDataDetail; - final RenderSourceLoader containerType; - public SectionDetailLayer(byte targetDataDetail, RenderSourceLoader containerType) { - this.targetDataDetail = targetDataDetail; - this.containerType = containerType; - } - } - - static void assertContainerTypeConfigCorrect() { - boolean isInFront = true; - for (int i = 0; i < layerLoaderConfig.size(); i++) { - if (layerLoaderConfig.get(i) == null) continue; - isInFront = false; - RenderSourceLoader entry = layerLoaderConfig.get(i); - if (i - entry.detailOffset < 0) { - throw new RuntimeException("ContainerTypeConfigEntry " + i + " has a levelOffset of " - + entry.detailOffset + " which makes the dataDetail be " + (i - entry.detailOffset) + "," + - " which is less than 0!"); - } - if (entry.detailOffset < 0) { - throw new RuntimeException("ContainerTypeConfigEntry " + i + " has a levelOffset of " - + entry.detailOffset + " which is less than 0!"); - } - } - if (layerLoaderConfig.get(layerLoaderConfig.size()-1) == null) { - throw new RuntimeException("The last ContainerTypeConfigEntry is null, which is invalid!"); - } - } - - final SectionDetailLayer[] sectionDetailLayers; + private final MovableGridRingList[] ringLists; public final int viewDistance; private final IRenderSourceProvider renderSourceProvider; @@ -105,63 +56,21 @@ public class LodQuadTree { */ public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ, IRenderSourceProvider provider) { renderSourceProvider = provider; - - assertContainerTypeConfigCorrect(); this.viewDistance = viewDistance; - //FIXME: Rework this mess of code! { // Calculate the max section detail - byte maxDetailLevel = getMaxDetailInRange(viewDistance * Math.sqrt(2)); - RenderSourceLoader finalEntry = null; - byte topSectionLevel = 0; - byte firstLevel = -1; - for (; topSectionLevel < layerLoaderConfig.size(); topSectionLevel++) { - if (layerLoaderConfig.get(topSectionLevel) == null) continue; - finalEntry = layerLoaderConfig.get(topSectionLevel); - if (firstLevel == -1) firstLevel = topSectionLevel; - if (topSectionLevel - finalEntry.detailOffset >= maxDetailLevel) break; - } - if (finalEntry == null) throw new RuntimeException("No container type found!"); - if (topSectionLevel == layerLoaderConfig.size()) - topSectionLevel = (byte) (maxDetailLevel + finalEntry.detailOffset); + byte maxDataDetailLevel = getMaxDetailInRange(viewDistance * Math.sqrt(2)); + byte topSectionLevel = getLayerSectionDetail(maxDataDetailLevel); numbersOfSectionLevels = (byte) (topSectionLevel + 1); - startingSectionLevel = firstLevel; - LOGGER.info("MaxLevel: " + maxDetailLevel + ", StartingLevel: " + startingSectionLevel + ", NumberOfLevels: " + numbersOfSectionLevels - + ", TopSectionLevel: " + topSectionLevel + ", FinalEntry: " + finalEntry); - sectionDetailLayers = new SectionDetailLayer[numbersOfSectionLevels - startingSectionLevel]; - ringLists = new MovableGridRingList[numbersOfSectionLevels - startingSectionLevel]; + ringLists = new MovableGridRingList[numbersOfSectionLevels - LAYER_BEGINNING_OFFSET]; } - { // Fill in the sectionDetailLayers info and construct the ringLists - byte lastNonNullEntry = -1; - for (byte i = startingSectionLevel; i < numbersOfSectionLevels; i++) { - byte targetDataDetail; - RenderSourceLoader containerType; - - if (i < layerLoaderConfig.size()) { - if (layerLoaderConfig.get(i) == null) { - if (lastNonNullEntry == -1) continue; - targetDataDetail = sectionDetailLayers[lastNonNullEntry].targetDataDetail; - containerType = null; - } else { - lastNonNullEntry = i; - RenderSourceLoader entry = layerLoaderConfig.get(i); - targetDataDetail = (byte) (i - entry.detailOffset); - containerType = entry; - } - } else { - LodUtil.assertTrue(layerLoaderConfig.get(layerLoaderConfig.size() - 1) != null, - "The last entry must not be null!"); - RenderSourceLoader entry = layerLoaderConfig.get(layerLoaderConfig.size() - 1); - targetDataDetail = (byte) (i - entry.detailOffset); - containerType = entry; - } - - LodUtil.assertTrue(targetDataDetail >= 0, "dataDetail must be >= 0!"); + { // Construct the ringLists + for (byte i = LAYER_BEGINNING_OFFSET; i < numbersOfSectionLevels; i++) { + byte targetDataDetail = getLayerDataDetail(i); int maxDist = getFurthestDistance(targetDataDetail); int halfSize = LodUtil.ceilDiv(maxDist, (1 << i) + 2); - sectionDetailLayers[i - startingSectionLevel] = new SectionDetailLayer(targetDataDetail, containerType); - ringLists[i - startingSectionLevel] = new MovableGridRingList(halfSize, + ringLists[i - LAYER_BEGINNING_OFFSET] = new MovableGridRingList<>(halfSize, initialPlayerX >> i, initialPlayerZ >> i); } } @@ -173,29 +82,18 @@ public class LodQuadTree { * @param pos the section positon. * @return the LodSection */ - public LodSection getSection(DhSectionPos pos) { + public LodRenderSection getSection(DhSectionPos pos) { return getSection(pos.sectionDetail, pos.sectionX, pos.sectionZ); } - public byte getFirstSectionDetailFromDataDetail(byte dataDetail) { - if (dataDetail <= startingSectionLevel) return startingSectionLevel; - for (byte i = 0; i < sectionDetailLayers.length; i++) { - if (sectionDetailLayers[i].targetDataDetail >= dataDetail) return (byte) (i + startingSectionLevel); - } - throw new RuntimeException("No section detail for dataDetail " + dataDetail+ " found!"); - } - public byte getDataDetail(byte sectionDetail) { - return sectionDetailLayers[sectionDetail - startingSectionLevel].targetDataDetail; - } - /** * This method returns the RingList of a given detail level * @apiNote The returned ringList should not be modified! * @param detailLevel the detail level * @return the RingList */ - public MovableGridRingList getRingList(byte detailLevel) { - return ringLists[detailLevel - startingSectionLevel]; + public MovableGridRingList getRingList(byte detailLevel) { + return ringLists[detailLevel - LAYER_BEGINNING_OFFSET]; } /** @@ -207,7 +105,7 @@ public class LodQuadTree { } public byte getStartingSectionLevel() { - return startingSectionLevel; + return LAYER_BEGINNING_OFFSET; } /** @@ -217,8 +115,8 @@ public class LodQuadTree { * @param z z coordinate of the section * @return the LodSection */ - public LodSection getSection(byte detailLevel, int x, int z) { - return ringLists[detailLevel - startingSectionLevel].get(x, z); + public LodRenderSection getSection(byte detailLevel, int x, int z) { + return ringLists[detailLevel - LAYER_BEGINNING_OFFSET].get(x, z); } @@ -263,7 +161,7 @@ public class LodQuadTree { * @param pos the section positon * @return the parent LodSection */ - public LodSection getParentSection(DhSectionPos pos) { + public LodRenderSection getParentSection(DhSectionPos pos) { return getSection(pos.getParent()); } @@ -274,7 +172,7 @@ public class LodQuadTree { * @param child0to3 since there are 4 possible children this index identify which one we are getting * @return one of the child LodSection */ - public LodSection getChildSection(DhSectionPos pos, int child0to3) { + public LodRenderSection getChildSection(DhSectionPos pos, int child0to3) { return getSection(pos.getChild(child0to3)); } @@ -283,10 +181,10 @@ public class LodQuadTree { * @param playerPos the reference position for the player */ public void tick(DhBlockPos2D playerPos) { - for (int sectLevel = startingSectionLevel; sectLevel < numbersOfSectionLevels; sectLevel++) { - ringLists[sectLevel - startingSectionLevel] + for (int sectLevel = LAYER_BEGINNING_OFFSET; sectLevel < numbersOfSectionLevels; sectLevel++) { + ringLists[sectLevel - LAYER_BEGINNING_OFFSET] .move(playerPos.x >> sectLevel, playerPos.z >> sectLevel, - LodSection::dispose); + LodRenderSection::dispose); } // First tick pass: update all sections' childCount from bottom level to top level. Step: @@ -318,14 +216,13 @@ public class LodQuadTree { // - If targetLevel < dataLevel@(sectLevel+1) && section == null: (use the next level's dataLevel) // - create new section with childCount = 0 // - Parent's childCount++ (Create parent if needed) - for (byte sectLevel = startingSectionLevel; sectLevel < numbersOfSectionLevels; sectLevel++) { - final MovableGridRingList ringList = ringLists[sectLevel - startingSectionLevel]; - final MovableGridRingList childRingList = - sectLevel == startingSectionLevel ? null : ringLists[sectLevel - startingSectionLevel - 1]; - final MovableGridRingList parentRingList = - sectLevel == numbersOfSectionLevels - 1 ? null : ringLists[sectLevel - startingSectionLevel + 1]; + for (byte sectLevel = LAYER_BEGINNING_OFFSET; sectLevel < numbersOfSectionLevels; sectLevel++) { + final MovableGridRingList ringList = ringLists[sectLevel - LAYER_BEGINNING_OFFSET]; + final MovableGridRingList childRingList = + sectLevel == LAYER_BEGINNING_OFFSET ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET - 1]; + final MovableGridRingList parentRingList = + sectLevel == numbersOfSectionLevels - 1 ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET + 1]; final byte f_sectLevel = sectLevel; - RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType; ringList.forEachPosOrdered((section, pos) -> { if (f_sectLevel == 0 && section != null) { section.childCount = 0; @@ -333,19 +230,19 @@ public class LodQuadTree { if (section != null && section.childCount != 0) { // Section will be in the unloaded state. LodUtil.assertTrue(parentRingList != null); - LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); + LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); if (parent == null) { parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1, - new LodSection(section.pos.getParent())); + new LodRenderSection(section.pos.getParent())); parent.childCount++; } LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0); for (byte i = 0; i < 4; i++) { DhSectionPos childPos = section.pos.getChild(i); - LodSection child = childRingList.get(childPos.sectionX, childPos.sectionZ); + LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ); if (child == null) { child = childRingList.setChained(childPos.sectionX, childPos.sectionZ, - new LodSection(childPos)); + new LodRenderSection(childPos)); child.childCount = 0; } else if (child.childCount == -1) { child.childCount = 0; @@ -357,31 +254,31 @@ public class LodQuadTree { byte targetLevel = calculateExpectedDetailLevel(playerPos, sectPos); if (f_sectLevel == numbersOfSectionLevels -1) { // Section is in the top level. - if (targetLevel > getDataDetail(f_sectLevel) && section != null) { + if (targetLevel > getLayerDataDetail(f_sectLevel) && section != null) { section.childCount = -1; } - if (targetLevel <= getDataDetail(f_sectLevel) && section == null) { + if (targetLevel <= getLayerDataDetail(f_sectLevel) && section == null) { section = ringList.setChained(pos.x, pos.y, - new LodSection(sectPos)); + new LodRenderSection(sectPos)); } } else { // Section is not the top level. So we also need to consider the parent. - if (targetLevel >= getDataDetail((byte) (f_sectLevel+1)) && section != null) { + if (targetLevel >= getLayerDataDetail((byte) (f_sectLevel+1)) && section != null) { LodUtil.assertTrue(parentRingList != null); - LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); + LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); LodUtil.assertTrue(parent != null); LodUtil.assertTrue(parent.childCount <= 4 && parent.childCount > 0); parent.childCount--; section.childCount = -1; } - if (targetLevel < getDataDetail((byte) (f_sectLevel+1)) && section == null) { + if (targetLevel < getLayerDataDetail((byte) (f_sectLevel+1)) && section == null) { section = ringList.setChained(pos.x, pos.y, - new LodSection(sectPos)); + new LodRenderSection(sectPos)); LodUtil.assertTrue(parentRingList != null); - LodSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); + LodRenderSection parent = parentRingList.get(pos.x >> 1, pos.y >> 1); if (parent == null) { parent = parentRingList.setChained(pos.x >> 1, pos.y >> 1, - new LodSection(sectPos.getParent())); + new LodRenderSection(sectPos.getParent())); } parent.childCount++; } @@ -397,7 +294,7 @@ public class LodQuadTree { } // Second tick pass: - // Cascade the layers that is in Always Cascade Mode from top to bottom. (layer's containerType == null) + // Cascade the layers that is in Always Cascade Mode from top to bottom. (Not yet exposed or used) // At the same time, load and unload sections (and can also be used to assert everything is working). Step: // ===Assertion steps=== // assert childCount == 4 || childCount == 0 || childCount == -1 @@ -412,26 +309,24 @@ public class LodQuadTree { // if childCount == -1: // (section can be loaded or unloaded, due to fast movement) // - set this section to null (TODO: Is this needed to be first or last or don't matter for concurrency?) // - If loaded unload section - for (byte sectLevel = (byte) (numbersOfSectionLevels - 1); sectLevel >= startingSectionLevel; sectLevel--) { - final MovableGridRingList ringList = ringLists[sectLevel - startingSectionLevel]; - final MovableGridRingList childRingList = - sectLevel == startingSectionLevel ? null : ringLists[sectLevel - startingSectionLevel - 1]; - final boolean doCacsade = sectionDetailLayers[sectLevel - startingSectionLevel].containerType == null; - RenderSourceLoader containerType = sectionDetailLayers[sectLevel - startingSectionLevel].containerType; - + for (byte sectLevel = (byte) (numbersOfSectionLevels - 1); sectLevel >= LAYER_BEGINNING_OFFSET; sectLevel--) { + final MovableGridRingList ringList = ringLists[sectLevel - LAYER_BEGINNING_OFFSET]; + final MovableGridRingList childRingList = + sectLevel == LAYER_BEGINNING_OFFSET ? null : ringLists[sectLevel - LAYER_BEGINNING_OFFSET - 1]; + final boolean doCascade = false; // TODO: Utilize this cascade mode or at least expose this option ringList.forEachPosOrdered((section, pos) -> { if (section == null) return; // Cascade layers - if (doCacsade && section.childCount == 0) { + if (doCascade && section.childCount == 0) { LodUtil.assertTrue(childRingList != null); // Create childs to cascade the layer. for (byte i = 0; i < 4; i++) { DhSectionPos childPos = section.pos.getChild(i); - LodSection child = childRingList.get(childPos.sectionX, childPos.sectionZ); + LodRenderSection child = childRingList.get(childPos.sectionX, childPos.sectionZ); if (child == null) { child = childRingList.setChained(childPos.sectionX, childPos.sectionZ, - new LodSection(childPos)); + new LodRenderSection(childPos)); child.childCount = 0; } else { LodUtil.assertTrue(child.childCount == -1, @@ -463,7 +358,7 @@ public class LodQuadTree { section.dispose(); } else { if (!section.isLoaded() && !section.isLoading()) { - section.load(renderSourceProvider, containerType); + section.load(renderSourceProvider); } if (section.childCount == 4) section.enableRender(this); if (section.childCount == 0) section.disableRender(); diff --git a/src/main/java/com/seibel/lod/core/a7/render/LodSection.java b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java similarity index 88% rename from src/main/java/com/seibel/lod/core/a7/render/LodSection.java rename to src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java index ec448c8eb..5dbbaa57d 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/LodSection.java +++ b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java @@ -1,15 +1,12 @@ package com.seibel.lod.core.a7.render; -import com.seibel.lod.core.a7.datatype.RenderSourceLoader; import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.datatype.LodRenderSource; import com.seibel.lod.core.a7.save.io.render.IRenderSourceProvider; import java.util.concurrent.CompletableFuture; -public class LodSection { - public static final int SUB_REGION_DATA_WIDTH = 16*16; - +public class LodRenderSection { public final DhSectionPos pos; /* Following used for LodQuadTree tick() method, and ONLY for that method! */ @@ -23,7 +20,7 @@ public class LodSection { private boolean isRenderEnabled = false; // Create sub region - public LodSection(DhSectionPos pos) { + public LodRenderSection(DhSectionPos pos) { this.pos = pos; } @@ -42,7 +39,7 @@ public class LodSection { isRenderEnabled = false; } - public void load(IRenderSourceProvider renderDataProvider, RenderSourceLoader renderDataSourceClass) { + public void load(IRenderSourceProvider renderDataProvider) { if (loadFuture != null || lodRenderSource != null) throw new IllegalStateException("Reloading is not supported!"); loadFuture = renderDataProvider.read(pos); } 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 49f501711..8283750bf 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 @@ -40,25 +40,28 @@ public class RenderBufferHandler { // the buffer is only unloaded if all children's buffers are ready. This will make the // transition between buffers no longer causing any flicker. public void update() { - LodSection section = target.getSection(pos); + LodRenderSection section = target.getSection(pos); // If this fails, there may be concurrent modification of the quad tree // (as this update() should be called from the same thread that calls update() on the quad tree) LodUtil.assertTrue(section != null); LodRenderSource container = section.getRenderContainer(); // Update self's render buffer state - boolean shouldRender = section.isLoaded(); + boolean shouldRender = section.canRender(); if (!shouldRender) { - RenderBuffer buff = renderBufferSlot.getAndSet(null); - if (buff != null) { - buff.close(); - } + //TODO: Does this really need to force the old buffer to not be rendered? +// RenderBuffer buff = renderBufferSlot.getAndSet(null); +// if (buff != null) { +// buff.close(); +// } } else { LodUtil.assertTrue(container != null); // section.isLoaded() should have ensured this container.trySwapRenderBuffer(target, renderBufferSlot); } // 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(); if (shouldHaveChildren) { if (children == null) { @@ -73,6 +76,9 @@ public class RenderBufferHandler { } } else { if (children != null) { + //FIXME: Concurrency issue here: If render thread is concurrently using the child's buffer, + // and this thread got priority to close the buffer, it causes a bug wher the render thread + // will be using a closed buffer!!!! RenderBufferNode[] childs = children; children = null; for (RenderBufferNode child : childs) { @@ -98,7 +104,7 @@ public class RenderBufferHandler { public RenderBufferHandler(LodQuadTree target) { this.target = target; - MovableGridRingList referenceList = target.getRingList((byte) (target.getNumbersOfSectionLevels() - 1)); + MovableGridRingList referenceList = target.getRingList((byte) (target.getNumbersOfSectionLevels() - 1)); Pos2D center = referenceList.getCenter(); renderBufferNodes = new MovableGridRingList<>(referenceList.getHalfSize(), center); } @@ -113,12 +119,12 @@ public class RenderBufferHandler { public void update() { byte topDetail = (byte) (target.getNumbersOfSectionLevels() - 1); - MovableGridRingList referenceList = target.getRingList(topDetail); + MovableGridRingList referenceList = target.getRingList(topDetail); Pos2D center = referenceList.getCenter(); renderBufferNodes.move(center.x, center.y, RenderBufferNode::close); // Note: may lock the list renderBufferNodes.forEachPosOrdered((node, pos) -> { DhSectionPos sectPos = new DhSectionPos(topDetail, pos.x, pos.y); - LodSection section = target.getSection(sectPos); + LodRenderSection section = target.getSection(sectPos); if (section == null) { // If section is null, but node exists, remove node diff --git a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java index e546e0698..a876c6f44 100644 --- a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java +++ b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderFileHandler.java @@ -1,6 +1,7 @@ package com.seibel.lod.core.a7.save.io.render; import com.google.common.collect.HashMultimap; +import com.seibel.lod.core.a7.datatype.EmptyRenderSource; import com.seibel.lod.core.a7.datatype.LodDataSource; import com.seibel.lod.core.a7.datatype.LodRenderSource; import com.seibel.lod.core.a7.datatype.RenderSourceLoader; @@ -111,7 +112,15 @@ public class RenderFileHandler implements IRenderSourceProvider { dataSourceProvider::isCacheValid, dataSourceProvider::read, level, computeDefaultFilePath(p), p)); - return metaFile.loadOrGetCached(renderCacheThread); + return metaFile.loadOrGetCached(renderCacheThread).handle( + (render, e) -> { + if (e != null) { + LOGGER.error("Uncaught error on {}:", pos, e); + } + if (render != null) return render; + return EmptyRenderSource.INSTANCE; + } + ); } /* diff --git a/src/main/java/com/seibel/lod/core/api/internal/a7/SharedApi.java b/src/main/java/com/seibel/lod/core/api/internal/a7/SharedApi.java index db70acb58..780aaf67b 100644 --- a/src/main/java/com/seibel/lod/core/api/internal/a7/SharedApi.java +++ b/src/main/java/com/seibel/lod/core/api/internal/a7/SharedApi.java @@ -7,9 +7,14 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import org.apache.logging.log4j.Logger; public class SharedApi { - public static DhWorld currentWorld; + public static final Logger LOGGER = DhLoggerBuilder.getLogger("DH Events"); public static IMinecraftSharedWrapper MC; - public static Logger LOGGER = DhLoggerBuilder.getLogger("DH Events"); + public static DhWorld currentWorld; + + //TODO: Should this be in core and able to be accessed by core, or should this be in common, and only effect + // how common calls back into the internal APIs? + public static boolean inDedicatedEnvironment; + public static WorldEnvironment getEnvironment() { return currentWorld==null ? null : currentWorld.environment; } diff --git a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFinder.java b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFinder.java index 59323b08b..7406f56eb 100644 --- a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFinder.java +++ b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFinder.java @@ -70,7 +70,7 @@ public class LodDimensionFinder public static final String THREAD_NAME = "Sub-Dimension-Finder"; public static final String DEFAULT_SAVE_DIMENSION_FOLDER = "_Default-Sub-Dimension"; - private PlayerData playerData = new PlayerData(MC); + private PlayerData playerData = null;//new PlayerData(MC); private PlayerData firstSeenPlayerData = null; private volatile LodDimension foundLodDimension = null; @@ -218,7 +218,7 @@ public class LodDimensionFinder if (firstSeenPlayerData == null) { firstSeenPlayerData = playerData; - playerData = new PlayerData(MC); + playerData = null;//new PlayerData(MC); } // relevant positions @@ -571,7 +571,7 @@ public class LodDimensionFinder // determine the playerData IMinecraftClientWrapper mc = SingletonHandler.get(IMinecraftClientWrapper.class); - PlayerData playerdata = new PlayerData(mc); + PlayerData playerdata = null;//new PlayerData(mc); // write the data to file CommentedFileConfig toml = CommentedFileConfig.builder(file).build();