First fix on light & impl render source direct write

This commit is contained in:
TomTheFurry
2022-08-09 16:08:54 +08:00
parent 6a49a100e7
commit 88ccc76045
9 changed files with 86 additions and 38 deletions
@@ -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.
*/
@@ -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;
}
@@ -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<ChunkSizedData> 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;
}
}
@@ -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
@@ -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));
@@ -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
@@ -19,7 +19,6 @@ public class LodRenderSection {
private LodRenderSource lodRenderSource;
private CompletableFuture<LodRenderSource> 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 +
'}';
}
}
@@ -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<LodRenderSource> source = _readCached(data.get());
if (source == null) return;
if (source.isDone()) source.join().update(chunkData);
if (source.isDone()) source.join().write(chunkData);
}
public CompletableFuture<Void> flushAndSave(ExecutorService renderCacheThread) {
@@ -20,7 +20,7 @@ public class DhClientServerWorld extends DhWorld implements IClientWorld, IServe
private final HashMap<ILevelWrapper, DhClientServerLevel> 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);