Add very rough client World support
This commit is contained in:
@@ -59,7 +59,6 @@ public class LodDataBuilder {
|
||||
public static boolean canGenerateLodFromChunk(IChunkWrapper chunk)
|
||||
{
|
||||
//return true;
|
||||
return chunk != null &&
|
||||
chunk.isLightCorrect();
|
||||
return chunk != null && chunk.isLightCorrect(); // TODO client only chunks return chunks with bad lighting, preventing chunk building (or transparent only chunks)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package com.seibel.lod.core.level;
|
||||
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.ChunkSizedFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.FullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.transformers.ChunkToLodBuilder;
|
||||
import com.seibel.lod.core.file.fullDatafile.IFullDataSourceProvider;
|
||||
import com.seibel.lod.core.file.renderfile.RenderSourceFileHandler;
|
||||
import com.seibel.lod.core.level.states.ClientRenderState;
|
||||
import com.seibel.lod.core.pos.DhLodPos;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.render.LodQuadTree;
|
||||
import com.seibel.lod.core.util.FileScanUtil;
|
||||
import com.seibel.lod.core.file.fullDatafile.RemoteFullDataFileHandler;
|
||||
@@ -12,6 +18,7 @@ import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.math.Mat4f;
|
||||
import com.seibel.lod.core.render.renderer.LodRenderer;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
@@ -24,34 +31,32 @@ import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class DhClientLevel implements IDhClientLevel
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
public final ClientOnlySaveStructure save;
|
||||
public final ClientOnlySaveStructure saveStructure;
|
||||
public final RemoteFullDataFileHandler dataFileHandler;
|
||||
public final RenderSourceFileHandler renderSourceFileHandler;
|
||||
public final RenderBufferHandler renderBufferHandler; //TODO: Should this be owned by renderer?
|
||||
public final ChunkToLodBuilder chunkToLodBuilder = new ChunkToLodBuilder();;
|
||||
public final IClientLevelWrapper level;
|
||||
public LodRenderer renderer = null;
|
||||
public LodQuadTree tree;
|
||||
|
||||
public final AtomicReference<ClientRenderState> ClientRenderStateRef = new AtomicReference<>();
|
||||
|
||||
|
||||
|
||||
public DhClientLevel(ClientOnlySaveStructure save, IClientLevelWrapper level)
|
||||
public DhClientLevel(ClientOnlySaveStructure saveStructure, IClientLevelWrapper level)
|
||||
{
|
||||
this.save = save;
|
||||
save.getDataFolder(level).mkdirs();
|
||||
save.getRenderCacheFolder(level).mkdirs();
|
||||
this.dataFileHandler = new RemoteFullDataFileHandler(this, save.getDataFolder(level));
|
||||
this.renderSourceFileHandler = new RenderSourceFileHandler(this.dataFileHandler, this, save.getRenderCacheFolder(level));
|
||||
this.tree = new LodQuadTree(this, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * 16,
|
||||
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, this.renderSourceFileHandler);
|
||||
this.renderBufferHandler = new RenderBufferHandler(this.tree);
|
||||
this.saveStructure = saveStructure;
|
||||
|
||||
saveStructure.getDataFolder(level).mkdirs();
|
||||
saveStructure.getRenderCacheFolder(level).mkdirs();
|
||||
this.dataFileHandler = new RemoteFullDataFileHandler(this, saveStructure.getDataFolder(level));
|
||||
|
||||
this.level = level;
|
||||
FileScanUtil.scanFiles(save, level, this.dataFileHandler, this.renderSourceFileHandler);
|
||||
LOGGER.info("Started DHLevel for {} with saves at {}", level, save);
|
||||
FileScanUtil.scanFiles(saveStructure, level, this.dataFileHandler, null);
|
||||
LOGGER.info("Started DHLevel for "+level+" with saves at "+ saveStructure);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,18 +70,82 @@ public class DhClientLevel implements IDhClientLevel
|
||||
@Override
|
||||
public void clientTick()
|
||||
{
|
||||
this.tree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
this.renderBufferHandler.update();
|
||||
ClientRenderState clientRenderState = this.ClientRenderStateRef.get();
|
||||
if (clientRenderState == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (clientRenderState.quadtree.blockRenderDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
|
||||
{
|
||||
if (!this.ClientRenderStateRef.compareAndSet(clientRenderState, null))
|
||||
{
|
||||
return; //If we fail, we'll just wait for the next tick
|
||||
}
|
||||
|
||||
IClientLevelWrapper levelWrapper = clientRenderState.clientLevel;
|
||||
clientRenderState.closeAsync().join(); //TODO: Make it async.
|
||||
clientRenderState = new ClientRenderState(this, levelWrapper);
|
||||
if (!this.ClientRenderStateRef.compareAndSet(null, clientRenderState))
|
||||
{
|
||||
//FIXME: How to handle this?
|
||||
LOGGER.warn("Failed to set render state due to concurrency after changing view distance");
|
||||
clientRenderState.closeAsync();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
clientRenderState.quadtree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
clientRenderState.renderer.bufferHandler.update();
|
||||
|
||||
this.chunkToLodBuilder.tick();
|
||||
}
|
||||
|
||||
|
||||
public void startRenderer(IClientLevelWrapper clientLevel)
|
||||
{
|
||||
LOGGER.info("Starting renderer for "+this);
|
||||
ClientRenderState ClientRenderState = new ClientRenderState(this, clientLevel);
|
||||
if (!this.ClientRenderStateRef.compareAndSet(null, ClientRenderState))
|
||||
{
|
||||
LOGGER.warn("Failed to start renderer due to concurrency");
|
||||
ClientRenderState.closeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
|
||||
{
|
||||
if (this.renderer == null)
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState == null)
|
||||
{
|
||||
this.renderer = new LodRenderer(this.renderBufferHandler);
|
||||
LOGGER.error("Tried to call render() on "+this+" when renderer has not been started!");
|
||||
return;
|
||||
}
|
||||
this.renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
|
||||
ClientRenderState.renderer.drawLODs(mcModelViewMatrix, mcProjectionMatrix, partialTicks, profiler);
|
||||
}
|
||||
|
||||
public void stopRenderer()
|
||||
{
|
||||
LOGGER.info("Stopping renderer for "+this);
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState == null)
|
||||
{
|
||||
LOGGER.warn("Tried to stop renderer for "+this+" when it was not started!");
|
||||
return;
|
||||
}
|
||||
|
||||
// stop the render state
|
||||
while (!this.ClientRenderStateRef.compareAndSet(ClientRenderState, null)) // TODO why is there a while loop here?
|
||||
{
|
||||
ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
ClientRenderState.closeAsync().join(); //TODO: Make it async.
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,28 +163,70 @@ public class DhClientLevel implements IDhClientLevel
|
||||
@Override
|
||||
public void clearRenderDataCache()
|
||||
{
|
||||
if (this.tree != null)
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState != null && ClientRenderState.quadtree != null)
|
||||
{
|
||||
this.tree.clearRenderDataCache();
|
||||
ClientRenderState.quadtree.clearRenderDataCache();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChunkAsync(IChunkWrapper chunk)
|
||||
{
|
||||
//TODO
|
||||
CompletableFuture<ChunkSizedFullDataSource> future = this.chunkToLodBuilder.tryGenerateData(chunk);
|
||||
if (future != null)
|
||||
{
|
||||
future.thenAccept(this::saveWrites);
|
||||
}
|
||||
}
|
||||
private void saveWrites(ChunkSizedFullDataSource data)
|
||||
{
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
DhLodPos pos = data.getBBoxLodPos().convertToDetailLevel(FullDataSource.SECTION_SIZE_OFFSET);
|
||||
if (ClientRenderState != null)
|
||||
{
|
||||
ClientRenderState.renderSourceFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() { return this.level.getMinHeight(); }
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> saveAsync() { return this.renderSourceFileHandler.flushAndSave(); }
|
||||
public CompletableFuture<Void> saveAsync()
|
||||
{
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState != null)
|
||||
{
|
||||
return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.dataFileHandler.flushAndSave(), (voidA, voidB) -> null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.dataFileHandler.flushAndSave();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
this.renderSourceFileHandler.close();
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState != null)
|
||||
{
|
||||
while (!this.ClientRenderStateRef.compareAndSet(ClientRenderState, null))
|
||||
{
|
||||
ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
ClientRenderState.closeAsync().join(); //TODO: Make this async.
|
||||
}
|
||||
|
||||
LOGGER.info("Closed DHLevel for "+this.level);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,17 +7,14 @@ import com.seibel.lod.core.dataObjects.fullData.sources.ChunkSizedFullDataSource
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.FullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.transformers.ChunkToLodBuilder;
|
||||
import com.seibel.lod.core.file.fullDatafile.IFullDataSourceProvider;
|
||||
import com.seibel.lod.core.file.renderfile.RenderSourceFileHandler;
|
||||
import com.seibel.lod.core.generation.BatchGenerator;
|
||||
import com.seibel.lod.core.generation.WorldGenerationQueue;
|
||||
import com.seibel.lod.core.level.states.ClientRenderState;
|
||||
import com.seibel.lod.core.pos.DhLodPos;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.render.LodQuadTree;
|
||||
import com.seibel.lod.core.file.fullDatafile.GeneratedFullDataFileHandler;
|
||||
import com.seibel.lod.core.util.FileScanUtil;
|
||||
import com.seibel.lod.core.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.render.RenderBufferHandler;
|
||||
import com.seibel.lod.core.file.structure.LocalSaveStructure;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
@@ -25,7 +22,6 @@ import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.logging.f3.F3Screen;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import com.seibel.lod.core.util.math.Mat4f;
|
||||
import com.seibel.lod.core.render.renderer.LodRenderer;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
@@ -96,47 +92,33 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
|
||||
@Override
|
||||
public void clientTick()
|
||||
{
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState == null)
|
||||
ClientRenderState clientRenderState = this.ClientRenderStateRef.get();
|
||||
if (clientRenderState == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ClientRenderState.quadtree.blockRenderDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
|
||||
if (clientRenderState.quadtree.blockRenderDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
|
||||
{
|
||||
if (!this.ClientRenderStateRef.compareAndSet(ClientRenderState, null))
|
||||
if (!this.ClientRenderStateRef.compareAndSet(clientRenderState, null))
|
||||
{
|
||||
return; //If we fail, we'll just wait for the next tick
|
||||
}
|
||||
|
||||
IClientLevelWrapper levelWrapper = ClientRenderState.clientLevel;
|
||||
ClientRenderState.closeAsync().join(); //TODO: Make it async.
|
||||
ClientRenderState = new ClientRenderState(this, levelWrapper);
|
||||
if (!this.ClientRenderStateRef.compareAndSet(null, ClientRenderState))
|
||||
IClientLevelWrapper levelWrapper = clientRenderState.clientLevel;
|
||||
clientRenderState.closeAsync().join(); //TODO: Make it async.
|
||||
clientRenderState = new ClientRenderState(this, levelWrapper);
|
||||
if (!this.ClientRenderStateRef.compareAndSet(null, clientRenderState))
|
||||
{
|
||||
//FIXME: How to handle this?
|
||||
LOGGER.warn("Failed to set render state due to concurrency after changing view distance");
|
||||
ClientRenderState.closeAsync();
|
||||
clientRenderState.closeAsync();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ClientRenderState.quadtree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
ClientRenderState.renderer.bufferHandler.update();
|
||||
}
|
||||
|
||||
private void saveWrites(ChunkSizedFullDataSource data)
|
||||
{
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
DhLodPos pos = data.getBBoxLodPos().convertToDetailLevel(FullDataSource.SECTION_SIZE_OFFSET);
|
||||
if (ClientRenderState != null)
|
||||
{
|
||||
ClientRenderState.renderSourceFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
|
||||
}
|
||||
clientRenderState.quadtree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
clientRenderState.renderer.bufferHandler.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -249,6 +231,19 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
|
||||
future.thenAccept(this::saveWrites);
|
||||
}
|
||||
}
|
||||
private void saveWrites(ChunkSizedFullDataSource data)
|
||||
{
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
DhLodPos pos = data.getBBoxLodPos().convertToDetailLevel(FullDataSource.SECTION_SIZE_OFFSET);
|
||||
if (ClientRenderState != null)
|
||||
{
|
||||
ClientRenderState.renderSourceFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpRamUsage()
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.seibel.lod.core.level.states;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.file.renderfile.RenderSourceFileHandler;
|
||||
import com.seibel.lod.core.level.DhClientLevel;
|
||||
import com.seibel.lod.core.level.DhClientServerLevel;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.render.LodQuadTree;
|
||||
@@ -27,7 +28,7 @@ public class ClientRenderState
|
||||
public final LodRenderer renderer;
|
||||
|
||||
|
||||
|
||||
// TODO combine
|
||||
public ClientRenderState(DhClientServerLevel parent, IClientLevelWrapper clientLevel)
|
||||
{
|
||||
this.clientLevel = clientLevel;
|
||||
@@ -40,6 +41,18 @@ public class ClientRenderState
|
||||
FileScanUtil.scanFiles(parent.saveStructure, parent.serverLevel, null, this.renderSourceFileHandler);
|
||||
this.renderer = new LodRenderer(renderBufferHandler);
|
||||
}
|
||||
public ClientRenderState(DhClientLevel parent, IClientLevelWrapper clientLevel)
|
||||
{
|
||||
this.clientLevel = clientLevel;
|
||||
this.renderSourceFileHandler = new RenderSourceFileHandler(parent.dataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.level));
|
||||
|
||||
this.quadtree = new LodQuadTree(parent, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH,
|
||||
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, this.renderSourceFileHandler);
|
||||
|
||||
RenderBufferHandler renderBufferHandler = new RenderBufferHandler(this.quadtree);
|
||||
FileScanUtil.scanFiles(parent.saveStructure, parent.level, null, this.renderSourceFileHandler);
|
||||
this.renderer = new LodRenderer(renderBufferHandler);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +52,10 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DhClientLevel(this.saveStructure, clientLevelWrapper);
|
||||
DhClientLevel level = new DhClientLevel(this.saveStructure, clientLevelWrapper);
|
||||
level.startRenderer(clientLevelWrapper);
|
||||
|
||||
return level;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,7 +96,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
DhClientLevel level = iterator.next();
|
||||
if (level.tree.blockRenderDistance != newBlockRenderDistance)
|
||||
if (level.ClientRenderStateRef.get().quadtree.blockRenderDistance != newBlockRenderDistance)
|
||||
{
|
||||
level.close();
|
||||
iterator.remove();
|
||||
|
||||
Reference in New Issue
Block a user