Move shared Dh(Server)ClientLevel code into AbstractDhClientLevel

This fixes DhServerClientLevel's crashing
This commit is contained in:
James Seibel
2023-02-25 21:31:18 -06:00
parent 2376baf936
commit 381d3fe216
8 changed files with 329 additions and 222 deletions
@@ -96,26 +96,33 @@ public class ClientApi
public void onClientOnlyConnected()
{
if (ENABLE_EVENT_LOGGING)
// only continue if the client is connected to a different server
if (MC.clientConnectedToDedicatedServer())
{
LOGGER.info("Client on ClientOnly mode connecting.");
if (ENABLE_EVENT_LOGGING)
{
LOGGER.info("Client on ClientOnly mode connecting.");
}
SharedApi.setDhWorld(new DhClientWorld());
}
SharedApi.setDhWorld(new DhClientWorld());
}
public void onClientOnlyDisconnected()
{
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null)
if (MC.clientConnectedToDedicatedServer())
{
if (ENABLE_EVENT_LOGGING)
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null)
{
LOGGER.info("Client on ClientOnly mode disconnecting.");
if (ENABLE_EVENT_LOGGING)
{
LOGGER.info("Client on ClientOnly mode disconnecting.");
}
world.close();
SharedApi.setDhWorld(null);
}
world.close();
SharedApi.setDhWorld(null);
}
}
@@ -22,10 +22,8 @@ public class SharedApi
public static void setDhWorld(AbstractDhWorld newWorld) { currentWorld = newWorld; }
public static AbstractDhWorld getAbstractDhWorld() { return currentWorld; }
/** returns null if the {@link SharedApi#currentWorld} isn't a {@link DhClientServerWorld} */
public static DhClientServerWorld getDhClientServerWorld() { return (currentWorld != null && DhClientServerWorld.class.isInstance(currentWorld)) ? (DhClientServerWorld) currentWorld : null; }
/** returns null if the {@link SharedApi#currentWorld} isn't a {@link DhClientWorld} or {@link DhClientServerWorld} */
public static IDhClientWorld getIDhClientWorld() { return (currentWorld != null && IDhClientWorld.class.isInstance(currentWorld)) ? (IDhClientWorld) currentWorld : null; }
/** returns null if the {@link SharedApi#currentWorld} isn't a {@link DhServerWorld} or {@link DhClientServerWorld} */
@@ -0,0 +1,277 @@
package com.seibel.lod.core.level;
import com.seibel.lod.core.config.Config;
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.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.file.fullDatafile.FullDataFileHandler;
import com.seibel.lod.core.file.fullDatafile.IFullDataSourceProvider;
import com.seibel.lod.core.file.fullDatafile.RemoteFullDataFileHandler;
import com.seibel.lod.core.file.structure.AbstractSaveStructure;
import com.seibel.lod.core.level.states.ClientRenderState;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.logging.f3.F3Screen;
import com.seibel.lod.core.pos.DhBlockPos2D;
import com.seibel.lod.core.pos.DhLodPos;
import com.seibel.lod.core.pos.DhSectionPos;
import com.seibel.lod.core.util.FileScanUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.util.math.Mat4f;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
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;
/**
* This contains code that is shared between {@link DhClientLevel} {@link DhClientServerLevel}
*/
public abstract class AbstractDhClientLevel implements IDhClientLevel
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final AbstractSaveStructure saveStructure;
public final ChunkToLodBuilder chunkToLodBuilder;
public FullDataFileHandler fullDataFileHandler;
public final AtomicReference<ClientRenderState> ClientRenderStateRef = new AtomicReference<>();
//=============//
// constructor //
//=============//
public AbstractDhClientLevel(AbstractSaveStructure saveStructure, ILevelWrapper levelWrapper)
{
this.saveStructure = saveStructure;
if (this.saveStructure.getFullDataFolder(levelWrapper).mkdirs())
{
LOGGER.warn("unable to create full data folder.");
}
if (this.saveStructure.getRenderCacheFolder(levelWrapper).mkdirs())
{
LOGGER.warn("unable to create cache folder.");
}
this.fullDataFileHandler = new RemoteFullDataFileHandler(this, this.saveStructure.getFullDataFolder(levelWrapper));
FileScanUtil.scanFiles(saveStructure, levelWrapper, this.fullDataFileHandler, null);
this.chunkToLodBuilder = new ChunkToLodBuilder();
}
//==============//
// tick methods //
//==============//
/**
* Includes logic used by both {@link DhClientServerLevel} and {@link DhClientServerLevel}
* @return whether the tick method completed
*/
protected boolean baseClientTick()
{
ClientRenderState clientRenderState = this.ClientRenderStateRef.get();
if (clientRenderState == null)
{
return false;
}
if (clientRenderState.quadtree.blockRenderDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
{
if (!this.ClientRenderStateRef.compareAndSet(clientRenderState, null))
{
return false; //If we fail, we'll just wait for the next tick
}
clientRenderState.closeAsync().join(); //TODO: Make it async.
clientRenderState = new ClientRenderState(this, this.fullDataFileHandler, this.saveStructure);
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 false;
}
}
clientRenderState.quadtree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
clientRenderState.renderer.bufferHandler.update();
return true;
}
//========//
// render //
//========//
/** @return if the {@link ClientRenderState} was successfully swapped */
protected boolean setAndStartRenderer()
{
ClientRenderState ClientRenderState = new ClientRenderState(this, this.fullDataFileHandler, this.saveStructure);
if (!this.ClientRenderStateRef.compareAndSet(null, ClientRenderState))
{
LOGGER.warn("Failed to start renderer due to concurrency");
ClientRenderState.closeAsync();
return false;
}
else
{
return true;
}
}
@Override
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState == null)
{
LOGGER.error("Tried to call render() on "+this+" when renderer has not been started!");
return;
}
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.
}
//===============//
// data handling //
//===============//
@Override
public void updateChunkAsync(IChunkWrapper chunk)
{
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.fullDataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
}
}
@Override
public CompletableFuture<Void> saveAsync()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null)
{
return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.fullDataFileHandler.flushAndSave(), (voidA, voidB) -> null);
}
else
{
return this.fullDataFileHandler.flushAndSave();
}
}
/** Includes logic used by both {@link DhClientServerLevel} and {@link DhClientServerLevel} */
protected void baseClose()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null)
{
// TODO does this have to be in a while loop, if so why?
while (!this.ClientRenderStateRef.compareAndSet(ClientRenderState, null))
{
ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState == null)
{
break;
}
}
if (ClientRenderState != null)
{
ClientRenderState.closeAsync().join(); //TODO: Make this async.
}
}
}
//=======================//
// misc helper functions //
//=======================//
@Override
public void dumpRamUsage()
{
//TODO
}
/** Returns what should be displayed in Minecraft's F3 debug menu */
protected String[] f3Log()
{
String dimName = this.getLevelWrapper().getDimensionType().getDimensionName();
ClientRenderState renderState = this.ClientRenderStateRef.get();
if (renderState == null)
{
return new String[] { "level @ "+dimName+": Inactive" };
}
else
{
return new String[] { "level @ "+dimName+": Active" };
}
}
@Override
public IFullDataSourceProvider getFileHandler() { return this.fullDataFileHandler; }
@Override
public void clearRenderDataCache()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null && ClientRenderState.quadtree != null)
{
ClientRenderState.quadtree.clearRenderDataCache();
}
}
}
@@ -12,8 +12,6 @@ import com.seibel.lod.core.pos.DhLodPos;
import com.seibel.lod.core.pos.DhSectionPos;
import com.seibel.lod.core.util.FileScanUtil;
import com.seibel.lod.core.file.fullDatafile.RemoteFullDataFileHandler;
import com.seibel.lod.core.pos.DhBlockPos2D;
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;
@@ -31,17 +29,16 @@ import org.apache.logging.log4j.Logger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
public class DhClientLevel implements IDhClientLevel
/** The level used when connected to a server */
public class DhClientLevel extends AbstractDhClientLevel implements IDhClientLevel
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final IClientLevelWrapper clientLevelWrapper;
public final AbstractSaveStructure saveStructure;
public final ChunkToLodBuilder chunkToLodBuilder;
private final IClientLevelWrapper clientLevelWrapper;
public final F3Screen.NestedMessage f3Message;
public FullDataFileHandler fullDataFileHandler;
public final AtomicReference<ClientRenderState> ClientRenderStateRef = new AtomicReference<>();
@@ -54,34 +51,10 @@ public class DhClientLevel implements IDhClientLevel
public DhClientLevel(AbstractSaveStructure saveStructure, IClientLevelWrapper clientLevelWrapper)
{
this(saveStructure, clientLevelWrapper, null);
super(saveStructure, clientLevelWrapper);
this.fullDataFileHandler = new RemoteFullDataFileHandler(this, this.saveStructure.getFullDataFolder(this.clientLevelWrapper));
FileScanUtil.scanFiles(saveStructure, this.clientLevelWrapper, this.fullDataFileHandler, null);
}
public DhClientLevel(AbstractSaveStructure saveStructure, IClientLevelWrapper clientLevelWrapper, FullDataFileHandler fullDataFileHandler)
{
this.clientLevelWrapper = clientLevelWrapper;
this.saveStructure = saveStructure;
if (this.saveStructure.getFullDataFolder(this.clientLevelWrapper).mkdirs())
{
LOGGER.warn("unable to create full data folder.");
}
if (this.saveStructure.getRenderCacheFolder(this.clientLevelWrapper).mkdirs())
{
LOGGER.warn("unable to create cache folder.");
}
// TODO not a great way of handling this, but it works for now
if (fullDataFileHandler != null)
{
this.fullDataFileHandler = fullDataFileHandler;
FileScanUtil.scanFiles(saveStructure, this.clientLevelWrapper, this.fullDataFileHandler, null);
}
this.f3Message = new F3Screen.NestedMessage(this::f3Log);
this.chunkToLodBuilder = new ChunkToLodBuilder();
this.f3Message = new F3Screen.NestedMessage(super::f3Log);
LOGGER.info("Started DHLevel for "+this.clientLevelWrapper+" with saves at "+this.saveStructure);
@@ -103,42 +76,6 @@ public class DhClientLevel implements IDhClientLevel
this.chunkToLodBuilder.tick();
}
/**
* Includes logic used by both {@link DhClientServerLevel} and {@link DhClientServerLevel}
* @return whether the tick method completed
*/
protected boolean baseClientTick()
{
ClientRenderState clientRenderState = this.ClientRenderStateRef.get();
if (clientRenderState == null)
{
return false;
}
if (clientRenderState.quadtree.blockRenderDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
{
if (!this.ClientRenderStateRef.compareAndSet(clientRenderState, null))
{
return false; //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 false;
}
}
clientRenderState.quadtree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
clientRenderState.renderer.bufferHandler.update();
return true;
}
@@ -151,55 +88,6 @@ public class DhClientLevel implements IDhClientLevel
LOGGER.info("Starting renderer for "+this);
this.setAndStartRenderer();
}
/** @return if the {@link ClientRenderState} was successfully swapped */
protected boolean setAndStartRenderer()
{
ClientRenderState ClientRenderState = new ClientRenderState(this, this.clientLevelWrapper);
if (!this.ClientRenderStateRef.compareAndSet(null, ClientRenderState))
{
LOGGER.warn("Failed to start renderer due to concurrency");
ClientRenderState.closeAsync();
return false;
}
else
{
return true;
}
}
@Override
public void render(Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState == null)
{
LOGGER.error("Tried to call render() on "+this+" when renderer has not been started!");
return;
}
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.
}
@@ -224,43 +112,6 @@ public class DhClientLevel implements IDhClientLevel
// data handling //
//===============//
@Override
public void updateChunkAsync(IChunkWrapper chunk)
{
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.fullDataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
}
}
@Override
public CompletableFuture<Void> saveAsync()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null)
{
return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.fullDataFileHandler.flushAndSave(), (voidA, voidB) -> null);
}
else
{
return this.fullDataFileHandler.flushAndSave();
}
}
@Override
@@ -269,28 +120,6 @@ public class DhClientLevel implements IDhClientLevel
this.baseClose();
LOGGER.info("Closed "+DhClientLevel.class.getSimpleName()+" for "+this.clientLevelWrapper);
}
/** Includes logic used by both {@link DhClientServerLevel} and {@link DhClientServerLevel} */
protected void baseClose()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null)
{
// TODO does this have to be in a while loop, if so why?
while (!this.ClientRenderStateRef.compareAndSet(ClientRenderState, null))
{
ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState == null)
{
break;
}
}
if (ClientRenderState != null)
{
ClientRenderState.closeAsync().join(); //TODO: Make this async.
}
}
}
@@ -299,22 +128,6 @@ public class DhClientLevel implements IDhClientLevel
// misc helper functions //
//=======================//
/** Returns what should be displayed in Minecraft's F3 debug menu */
protected String[] f3Log()
{
ClientRenderState renderState = this.ClientRenderStateRef.get();
if (renderState == null)
{
return new String[] { LodUtil.formatLog("level @ {}: Inactive", this.clientLevelWrapper.getDimensionType().getDimensionName()) };
}
else
{
return new String[] {
LodUtil.formatLog("level @ {}: Active", this.clientLevelWrapper.getDimensionType().getDimensionName())
};
}
}
@Override
public void dumpRamUsage()
{
@@ -334,6 +147,4 @@ public class DhClientLevel implements IDhClientLevel
}
}
}
@@ -9,11 +9,14 @@ import com.seibel.lod.core.file.structure.AbstractSaveStructure;
import com.seibel.lod.core.generation.BatchGenerator;
import com.seibel.lod.core.generation.WorldGenerationQueue;
import com.seibel.lod.core.file.fullDatafile.GeneratedFullDataFileHandler;
import com.seibel.lod.core.level.states.ClientRenderState;
import com.seibel.lod.core.logging.f3.F3Screen;
import com.seibel.lod.core.util.FileScanUtil;
import com.seibel.lod.core.pos.DhBlockPos2D;
import com.seibel.lod.core.config.Config;
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.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
@@ -26,15 +29,16 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
/** The level used on a singleplayer world */
public class DhClientServerLevel extends DhClientLevel implements IDhClientLevel, IDhServerLevel
public class DhClientServerLevel extends AbstractDhClientLevel implements IDhClientLevel, IDhServerLevel
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final IServerLevelWrapper serverLevelWrapper;
public final F3Screen.NestedMessage f3Message;
/**
* This is separate from {@link DhClientLevel#fullDataFileHandler} and included
* This is separate from {@link AbstractDhClientLevel#fullDataFileHandler}
* since the base {@link FullDataFileHandler} doesn't support world generation
*/
public final GeneratedFullDataFileHandler generatedFullDataFileHandler;
@@ -46,12 +50,14 @@ public class DhClientServerLevel extends DhClientLevel implements IDhClientLevel
public DhClientServerLevel(AbstractSaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper)
{
super(saveStructure, serverLevelWrapper.tryGetClientLevelWrapper(), null);
super(saveStructure, serverLevelWrapper);
this.serverLevelWrapper = serverLevelWrapper;
this.f3Message = new F3Screen.NestedMessage(super::f3Log);
this.generatedFullDataFileHandler = new GeneratedFullDataFileHandler(this, saveStructure.getFullDataFolder(serverLevelWrapper));
this.fullDataFileHandler = this.generatedFullDataFileHandler;
FileScanUtil.scanFiles(saveStructure, this.serverLevelWrapper, this.fullDataFileHandler, null);
this.worldGeneratorEnabledConfig = new AppliedConfigState<>(Config.Client.WorldGenerator.enableDistantGeneration);
@@ -174,7 +180,7 @@ public class DhClientServerLevel extends DhClientLevel implements IDhClientLevel
// level handling //
//================//
@Override //FIXME this can fail if the clientLevel hasn't been created yet
@Override //FIXME this can fail if the clientLevel isn't available yet, maybe in that case we could return -1 and handle it upstream?
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block)
{
IClientLevelWrapper clientLevel = this.getClientLevelWrapper();
@@ -188,6 +194,8 @@ public class DhClientServerLevel extends DhClientLevel implements IDhClientLevel
}
}
@Override
public IClientLevelWrapper getClientLevelWrapper() { return this.serverLevelWrapper.tryGetClientLevelWrapper(); }
@Override
public IServerLevelWrapper getServerLevelWrapper() { return this.serverLevelWrapper; }
@Override
@@ -13,7 +13,10 @@ public interface IDhLevel extends AutoCloseable
void dumpRamUsage();
/** May return either a client or server level wrapper. */
/**
* May return either a client or server level wrapper. <br>
* Should not return null
*/
ILevelWrapper getLevelWrapper();
void updateChunkAsync(IChunkWrapper chunk);
@@ -2,9 +2,10 @@ 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.fullDatafile.IFullDataSourceProvider;
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.file.structure.AbstractSaveStructure;
import com.seibel.lod.core.level.IDhClientLevel;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.render.LodQuadTree;
import com.seibel.lod.core.render.RenderBufferHandler;
@@ -12,7 +13,7 @@ import com.seibel.lod.core.render.renderer.LodRenderer;
import com.seibel.lod.core.util.FileScanUtil;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Logger;
import java.util.concurrent.CompletableFuture;
@@ -22,23 +23,24 @@ public class ClientRenderState
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final IClientLevelWrapper clientLevel;
public final ILevelWrapper levelWrapper;
public final LodQuadTree quadtree;
public final RenderSourceFileHandler renderSourceFileHandler;
public final LodRenderer renderer;
public ClientRenderState(DhClientLevel parent, IClientLevelWrapper clientLevel)
public ClientRenderState(IDhClientLevel dhClientLevel, IFullDataSourceProvider fullDataSourceProvider,
AbstractSaveStructure saveStructure)
{
this.clientLevel = clientLevel;
this.renderSourceFileHandler = new RenderSourceFileHandler(parent.fullDataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.getLevelWrapper()));
this.levelWrapper = dhClientLevel.getLevelWrapper();
this.renderSourceFileHandler = new RenderSourceFileHandler(fullDataSourceProvider, dhClientLevel, saveStructure.getFullDataFolder(this.levelWrapper));
this.quadtree = new LodQuadTree(parent, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH,
this.quadtree = new LodQuadTree(dhClientLevel, 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.getLevelWrapper(), null, this.renderSourceFileHandler);
FileScanUtil.scanFiles(saveStructure, this.levelWrapper, fullDataSourceProvider, this.renderSourceFileHandler);
this.renderer = new LodRenderer(renderBufferHandler);
}
@@ -59,6 +59,7 @@ public interface IMinecraftClientWrapper extends IBindable
float getShade(ELodDirection lodDirection);
boolean hasSinglePlayerServer();
boolean clientConnectedToDedicatedServer();
String getCurrentServerName();
String getCurrentServerIp();