From 88ccc76045868016018bb2036b4228f9d7f4aa9b Mon Sep 17 00:00:00 2001 From: TomTheFurry Date: Tue, 9 Aug 2022 16:08:54 +0800 Subject: [PATCH] First fix on light & impl render source direct write --- .../lod/core/a7/datatype/LodRenderSource.java | 10 +--- .../a7/datatype/PlaceHolderRenderSource.java | 6 +- .../datatype/column/ColumnRenderSource.java | 30 ++++++---- .../transform/FullToColumnTransformer.java | 55 ++++++++++++++++++- .../a7/datatype/transform/LodDataBuilder.java | 4 +- .../lod/core/a7/render/LodQuadTree.java | 2 +- .../lod/core/a7/render/LodRenderSection.java | 8 +-- .../a7/save/io/render/RenderMetaFile.java | 7 +-- .../core/a7/world/DhClientServerWorld.java | 2 +- 9 files changed, 86 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java index e6dfa1ae1..0ad7c46a7 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/LodRenderSource.java @@ -2,14 +2,10 @@ package com.seibel.lod.core.a7.datatype; import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; import com.seibel.lod.core.a7.level.IClientLevel; -import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.render.LodQuadTree; import com.seibel.lod.core.a7.render.RenderBuffer; -import com.seibel.lod.core.a7.save.io.file.DataMetaFile; import com.seibel.lod.core.a7.save.io.render.RenderMetaFile; -import com.seibel.lod.core.objects.DHChunkPos; -import com.seibel.lod.core.objects.DHRegionPos; import java.io.IOException; import java.io.OutputStream; @@ -24,6 +20,7 @@ public interface LodRenderSource { void dispose(); // notify the container that the parent lodSection is now disposed (can be in loaded or unloaded state) byte getDetailOffset(); + /** * Try and swap in new render buffer for this section. Note that before this call, there should be no other * places storing or referencing the render buffer. @@ -34,12 +31,11 @@ public interface LodRenderSource { void saveRender(IClientLevel level, RenderMetaFile file, OutputStream dataStream) throws IOException; - void update(ChunkSizedData chunkData); + void write(ChunkSizedData chunkData); + void flushWrites(IClientLevel level); byte getRenderVersion(); - void markInvalid(); - /** * Whether this object is still valid. If not, a new one should be created. */ diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/PlaceHolderRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/PlaceHolderRenderSource.java index 3a5e4c8a5..983ee9423 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/PlaceHolderRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/PlaceHolderRenderSource.java @@ -49,14 +49,16 @@ public class PlaceHolderRenderSource implements LodRenderSource { throw new UnsupportedOperationException("EmptyRenderSource should NEVER be saved!"); } @Override - public void update(ChunkSizedData chunkData) {} + public void write(ChunkSizedData chunkData) {} + + @Override + public void flushWrites(IClientLevel level) {} @Override public byte getRenderVersion() { return 0; } - @Override public void markInvalid() { isValid = false; } 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 f7fdb1165..a25868561 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 @@ -6,6 +6,7 @@ import com.seibel.lod.core.a7.datatype.column.accessor.ColumnQuadView; import com.seibel.lod.core.a7.datatype.column.accessor.IColumnDatatype; import com.seibel.lod.core.a7.datatype.column.render.ColumnRenderBuffer; import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; +import com.seibel.lod.core.a7.datatype.transform.FullToColumnTransformer; import com.seibel.lod.core.a7.level.IClientLevel; import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.render.RenderBuffer; @@ -26,6 +27,7 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicReference; public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { @@ -321,17 +323,27 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { @Override public void saveRender(IClientLevel level, RenderMetaFile file, OutputStream dataStream) throws IOException { + flushWrites(level); try (DataOutputStream dos = new DataOutputStream(dataStream)) { writeData(dos); } } - @Override - public void update(ChunkSizedData chunkData) { - //TODO Update render data directly + private final ConcurrentLinkedQueue writeRequest = new ConcurrentLinkedQueue<>(); - //TEMP DEUBG - isValid = false; + @Override + public void write(ChunkSizedData chunkData) { + writeRequest.add(chunkData); + } + @Override + public void flushWrites(IClientLevel level) { + boolean didSomething = false; + while (!writeRequest.isEmpty()) { + ChunkSizedData chunkData = writeRequest.poll(); + FullToColumnTransformer.writeFullDataChunkToColumnData(this, level, chunkData); + didSomething = true; + } + if (didSomething) lastNs = -1; // Reset the timeout to allow rebuilding the buffer again } @Override @@ -339,14 +351,8 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { return LATEST_VERSION; } - private boolean isValid = true; - @Override - public void markInvalid() { - isValid = false; - } - @Override public boolean isValid() { - return isValid; + return true; } } diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/transform/FullToColumnTransformer.java b/src/main/java/com/seibel/lod/core/a7/datatype/transform/FullToColumnTransformer.java index 98c994bc9..01c85d986 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/transform/FullToColumnTransformer.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/transform/FullToColumnTransformer.java @@ -3,6 +3,8 @@ package com.seibel.lod.core.a7.datatype.transform; import com.seibel.lod.core.a7.datatype.column.accessor.ColumnFormat; import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource; import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView; +import com.seibel.lod.core.a7.datatype.column.accessor.ColumnQuadView; +import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; import com.seibel.lod.core.a7.datatype.full.FullDataSource; import com.seibel.lod.core.a7.datatype.full.FullFormat; import com.seibel.lod.core.a7.datatype.full.IdBiomeBlockStateMap; @@ -60,11 +62,60 @@ public class FullToColumnTransformer { throw new UnsupportedOperationException("To be implemented"); //FIXME: Implement different size creation of renderData } - - return columnSource; } + public static void writeFullDataChunkToColumnData(ColumnRenderSource render, IClientLevel level, ChunkSizedData data) { + if (data.dataDetail != 0) + throw new UnsupportedOperationException("To be implemented"); + + final DhSectionPos pos = render.getSectionPos(); + final int renderOffsetX = (data.x*16) - pos.getCorner().getCorner().x; + final int renderOffsetZ = (data.z*16) - pos.getCorner().getCorner().z; + final int blockX = pos.getCorner().getCorner().x; + final int blockZ = pos.getCorner().getCorner().z; + final int perRenderWidth = 1 << render.getDataDetail(); + final int perDataWidth = 1 << data.dataDetail; + if (data.dataDetail == render.getDataDetail()) { + if (renderOffsetX < 0 || renderOffsetX+16 > render.getDataSize() || renderOffsetZ < 0 || renderOffsetZ+16 > render.getDataSize()) + throw new IllegalArgumentException("Data offset is out of bounds"); + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + ColumnArrayView columnArrayView = render.getVerticalDataView(renderOffsetX + x, renderOffsetZ + z); + SingleFullArrayView fullArrayView = data.get(x, z); + convertColumnData(level, blockX + perRenderWidth * (renderOffsetX+x), + blockZ + perRenderWidth * (renderOffsetZ+z), + columnArrayView, fullArrayView); + if (fullArrayView.doesItExist()) LodUtil.assertTrue(render.doesItExist(renderOffsetX + x, renderOffsetZ + z)); + } + } + } else { + final int dataPerRender = 1 << (render.getDataDetail() - data.dataDetail); + final int dataSize = 16 / dataPerRender; + final int vertSize = render.getVerticalSize(); + long[] tempRender = new long[dataPerRender * dataPerRender * vertSize]; + if (renderOffsetX < 0 || renderOffsetX+dataSize > render.getDataSize() || renderOffsetZ < 0 || renderOffsetZ+dataSize > render.getDataSize()) + throw new IllegalArgumentException("Data offset is out of bounds"); + for (int x = 0; x < dataSize; x++) { + for (int z = 0; z < dataSize; z++) { + + ColumnQuadView tempQuadView = new ColumnQuadView(tempRender, dataPerRender, vertSize, 0, 0, dataPerRender, dataPerRender); + for (int ox = 0; ox < dataPerRender; ox++) { + for (int oz = 0; oz < dataPerRender; oz++) { + ColumnArrayView columnArrayView = tempQuadView.get(ox, oz); + SingleFullArrayView fullArrayView = data.get(x*dataPerRender+ox, z*dataPerRender+oz); + convertColumnData(level, blockX + perRenderWidth * (renderOffsetX+x) + perDataWidth * ox, + blockZ + perRenderWidth * (renderOffsetZ+z) + perDataWidth * oz, + columnArrayView, fullArrayView); + } + } + ColumnArrayView downSampledArrayView = render.getVerticalDataView(renderOffsetX + x, renderOffsetZ + z); + downSampledArrayView.mergeMultiDataFrom(tempQuadView); + } + } + } + } + private static void convertColumnData(IClientLevel level, int blockX, int blockZ, ColumnArrayView columnArrayView, SingleFullArrayView fullArrayView) { if (!fullArrayView.doesItExist()) return; // TODO: Set gen mode 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 09a3fbbf0..f60b27a6c 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 @@ -24,13 +24,13 @@ public class LodDataBuilder { IBiomeWrapper biome = chunk.getBiome(x, lastY, z); IBlockStateWrapper blockState = AIR; int mappedId = chunkData.getMapping().setAndGetId(biome, blockState); - byte light = (byte) (chunk.getBlockLight(x,lastY,z) << 4 + chunk.getSkyLight(x,lastY,z)); + byte light = (byte) ((chunk.getBlockLight(x,lastY,z) << 4) + chunk.getSkyLight(x,lastY,z)); int y=chunk.getMaxY(x, z); for (; y>=chunk.getMinBuildHeight(); y--) { IBiomeWrapper newBiome = chunk.getBiome(x, y, z); IBlockStateWrapper newBlockState = chunk.getBlockState(x, y, z); - byte newLight = (byte) (chunk.getBlockLight(x,y,z) << 4 + chunk.getSkyLight(x,y,z)); + byte newLight = (byte) ((chunk.getBlockLight(x,y,z) << 4) + chunk.getSkyLight(x,y,z)); if (!newBiome.equals(biome) || !newBlockState.equals(blockState)) { longs.add(FullFormat.encode(mappedId, lastY-y, y+1 - chunk.getMinBuildHeight(), light)); 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 935961cfe..db5494f93 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 @@ -414,7 +414,7 @@ public class LodQuadTree implements AutoCloseable { } if (section.childCount == 4) section.disableRender(); if (section.childCount == 0) section.enableRender(level, this); - section.tick(this); + section.tick(this, level); } // Assertion steps 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 ee43ebcf8..36d16b025 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 @@ -19,7 +19,6 @@ public class LodRenderSection { private LodRenderSource lodRenderSource; private CompletableFuture loadFuture; private boolean isRenderEnabled = false; - private IClientLevel level; //FIXME: Hack to pass level into enableRender() for renderSource // Create sub region public LodRenderSection(DhSectionPos pos) { @@ -31,12 +30,10 @@ public class LodRenderSection { if (lodRenderSource != null) { lodRenderSource.enableRender(level, quadTree); } - this.level = level; isRenderEnabled = true; } public void disableRender() { if (!isRenderEnabled) return; - level = null; if (lodRenderSource != null) { lodRenderSource.disableRender(); } @@ -55,13 +52,15 @@ public class LodRenderSection { loadFuture = renderDataProvider.read(pos); } - public void tick(LodQuadTree quadTree) { + public void tick(LodQuadTree quadTree, IClientLevel level) { if (loadFuture != null && loadFuture.isDone()) { lodRenderSource = loadFuture.join(); loadFuture = null; if (isRenderEnabled) { lodRenderSource.enableRender(level, quadTree); } + } else if (lodRenderSource != null) { + lodRenderSource.flushWrites(level); } } @@ -106,7 +105,6 @@ public class LodRenderSection { ", lodRenderSource=" + lodRenderSource + ", loadFuture=" + loadFuture + ", isRenderEnabled=" + isRenderEnabled + - ", level=" + level + '}'; } } 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 bdaa74cad..ab87d1f82 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 @@ -4,23 +4,18 @@ import com.seibel.lod.core.a7.datatype.LodDataSource; import com.seibel.lod.core.a7.datatype.LodRenderSource; import com.seibel.lod.core.a7.datatype.RenderSourceLoader; import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; -import com.seibel.lod.core.a7.datatype.full.FullFormat; import com.seibel.lod.core.a7.datatype.transform.DataRenderTransformer; import com.seibel.lod.core.a7.level.IClientLevel; -import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.pos.DhLodPos; import com.seibel.lod.core.a7.save.io.MetaFile; import com.seibel.lod.core.a7.pos.DhSectionPos; -import com.seibel.lod.core.a7.save.io.file.DataMetaFile; import com.seibel.lod.core.util.LodUtil; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.ref.SoftReference; -import java.util.Optional; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class RenderMetaFile extends MetaFile { @@ -42,7 +37,7 @@ public class RenderMetaFile extends MetaFile { CompletableFuture source = _readCached(data.get()); if (source == null) return; - if (source.isDone()) source.join().update(chunkData); + if (source.isDone()) source.join().write(chunkData); } public CompletableFuture flushAndSave(ExecutorService renderCacheThread) { diff --git a/src/main/java/com/seibel/lod/core/a7/world/DhClientServerWorld.java b/src/main/java/com/seibel/lod/core/a7/world/DhClientServerWorld.java index 3d79f3f84..55528a9fb 100644 --- a/src/main/java/com/seibel/lod/core/a7/world/DhClientServerWorld.java +++ b/src/main/java/com/seibel/lod/core/a7/world/DhClientServerWorld.java @@ -20,7 +20,7 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe private final HashMap levels; public final LocalSaveStructure saveStructure; public ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHTickerThread", 2); - public EventLoop eventLoop = new EventLoop(dhTickerThread, this::_clientTick); + public EventLoop eventLoop = new EventLoop(dhTickerThread, this::_clientTick); //TODO: Rate-limit the loop public DhClientServerWorld() { super(WorldEnvironment.Client_Server);