Move shared Dh(Server)ClientLevel code into AbstractDhClientLevel
This fixes DhServerClientLevel's crashing
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -59,6 +59,7 @@ public interface IMinecraftClientWrapper extends IBindable
|
||||
float getShade(ELodDirection lodDirection);
|
||||
|
||||
boolean hasSinglePlayerServer();
|
||||
boolean clientConnectedToDedicatedServer();
|
||||
|
||||
String getCurrentServerName();
|
||||
String getCurrentServerIp();
|
||||
|
||||
Reference in New Issue
Block a user