equalize DhClientLevel and DhClientServerLevel

This commit is contained in:
James Seibel
2023-02-25 15:43:20 -06:00
parent 8d5926fb2d
commit 5579b1dc95
5 changed files with 211 additions and 114 deletions
@@ -4,15 +4,13 @@ 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.logging.f3.F3Screen;
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;
import com.seibel.lod.core.pos.DhBlockPos2D;
import com.seibel.lod.core.render.RenderBufferHandler;
import com.seibel.lod.core.file.structure.ClientOnlySaveStructure;
import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
@@ -20,7 +18,6 @@ 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;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
@@ -37,36 +34,69 @@ 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 saveStructure;
public final RemoteFullDataFileHandler dataFileHandler;
public final ChunkToLodBuilder chunkToLodBuilder = new ChunkToLodBuilder();;
public final IClientLevelWrapper level;
public final RemoteFullDataFileHandler fullDataFileHandler;
public final ChunkToLodBuilder chunkToLodBuilder;
public final IClientLevelWrapper clientLevel;
public F3Screen.NestedMessage f3Message;
public final AtomicReference<ClientRenderState> ClientRenderStateRef = new AtomicReference<>();
public DhClientLevel(ClientOnlySaveStructure saveStructure, IClientLevelWrapper level)
public DhClientLevel(ClientOnlySaveStructure saveStructure, IClientLevelWrapper clientLevel)
{
this.clientLevel = clientLevel;
this.saveStructure = saveStructure;
saveStructure.getDataFolder(clientLevel).mkdirs();
saveStructure.getRenderCacheFolder(clientLevel).mkdirs();
saveStructure.getDataFolder(level).mkdirs();
saveStructure.getRenderCacheFolder(level).mkdirs();
this.dataFileHandler = new RemoteFullDataFileHandler(this, saveStructure.getDataFolder(level));
this.fullDataFileHandler = new RemoteFullDataFileHandler(this, saveStructure.getDataFolder(clientLevel));
FileScanUtil.scanFiles(saveStructure, clientLevel, this.fullDataFileHandler, null);
this.level = level;
FileScanUtil.scanFiles(saveStructure, level, this.dataFileHandler, null);
LOGGER.info("Started DHLevel for "+level+" with saves at "+ saveStructure);
this.f3Message = new F3Screen.NestedMessage(this::f3Log);
this.chunkToLodBuilder = new ChunkToLodBuilder();
LOGGER.info("Started DHLevel for "+clientLevel+" with saves at "+saveStructure);
}
//=======================//
// misc helper functions //
//=======================//
/** Returns what should be displayed in Minecraft's F3 debug menu */
private String[] f3Log()
{
ClientRenderState rs = this.ClientRenderStateRef.get();
if (rs == null)
{
return new String[] { LodUtil.formatLog("level @ {}: Inactive", this.clientLevel.getDimensionType().getDimensionName()) };
}
else
{
return new String[] {
LodUtil.formatLog("level @ {}: Active", this.clientLevel.getDimensionType().getDimensionName())
};
}
}
@Override
public void dumpRamUsage()
{
//TODO
}
//==============//
// tick methods //
//==============//
@Override
public void clientTick()
{
@@ -102,6 +132,11 @@ public class DhClientLevel implements IDhClientLevel
}
//========//
// render //
//========//
public void startRenderer(IClientLevelWrapper clientLevel)
{
LOGGER.info("Starting renderer for "+this);
@@ -148,28 +183,45 @@ public class DhClientLevel implements IDhClientLevel
}
@Override
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) { return 0; /* TODO */ }
//================//
// level handling //
//================//
@Override
public IClientLevelWrapper getClientLevelWrapper() { return this.level; }
@Override
public ILevelWrapper getLevelWrapper() { return this.level; }
@Override
public IFullDataSourceProvider getFileHandler() { return this.dataFileHandler; }
@Override
public void clearRenderDataCache()
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block)
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null && ClientRenderState.quadtree != null)
IClientLevelWrapper clientLevel = this.getClientLevelWrapper();
if (clientLevel == null)
{
ClientRenderState.quadtree.clearRenderDataCache();
return 0;
}
else
{
return clientLevel.computeBaseColor(pos, biome, block);
}
}
@Override
public IClientLevelWrapper getClientLevelWrapper()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
return ClientRenderState == null ? null : ClientRenderState.clientLevel;
}
@Override
public ILevelWrapper getLevelWrapper() { return this.clientLevel; }
@Override
public int getMinY() { return this.clientLevel.getMinHeight(); }
//===============//
// data handling //
//===============//
@Override
public void updateChunkAsync(IChunkWrapper chunk)
{
@@ -189,27 +241,26 @@ public class DhClientLevel implements IDhClientLevel
}
else
{
this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
this.fullDataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
}
}
@Override
public int getMinY() { return this.level.getMinHeight(); }
@Override
public CompletableFuture<Void> saveAsync()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null)
{
return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.dataFileHandler.flushAndSave(), (voidA, voidB) -> null);
return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.fullDataFileHandler.flushAndSave(), (voidA, voidB) -> null);
}
else
{
return this.dataFileHandler.flushAndSave();
return this.fullDataFileHandler.flushAndSave();
}
}
@Override
public void close()
{
@@ -227,7 +278,22 @@ public class DhClientLevel implements IDhClientLevel
ClientRenderState.closeAsync().join(); //TODO: Make this async.
}
LOGGER.info("Closed DHLevel for "+this.level);
LOGGER.info("Closed DHLevel for "+this.clientLevel);
}
@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();
}
}
}
@@ -43,10 +43,10 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
public final LocalSaveStructure saveStructure;
public final GeneratedFullDataFileHandler dataFileHandler;
public final GeneratedFullDataFileHandler fullDataFileHandler;
public final ChunkToLodBuilder chunkToLodBuilder;
public final IServerLevelWrapper serverLevel;
private final AppliedConfigState<Boolean> generatorEnabled;
private final AppliedConfigState<Boolean> worldGeneratorEnabledConfig;
public F3Screen.NestedMessage f3Message;
private final AtomicReference<ClientRenderState> ClientRenderStateRef = new AtomicReference<>();
@@ -54,25 +54,32 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
public DhClientServerLevel(LocalSaveStructure saveStructure, IServerLevelWrapper level)
public DhClientServerLevel(LocalSaveStructure saveStructure, IServerLevelWrapper serverLevel)
{
this.serverLevel = level;
this.serverLevel = serverLevel;
this.saveStructure = saveStructure;
saveStructure.getDataFolder(level).mkdirs();
saveStructure.getRenderCacheFolder(level).mkdirs();
saveStructure.getDataFolder(serverLevel).mkdirs();
saveStructure.getRenderCacheFolder(serverLevel).mkdirs();
this.dataFileHandler = new GeneratedFullDataFileHandler(this, saveStructure.getDataFolder(level));
FileScanUtil.scanFiles(saveStructure, this.serverLevel, this.dataFileHandler, null);
this.fullDataFileHandler = new GeneratedFullDataFileHandler(this, saveStructure.getDataFolder(serverLevel));
FileScanUtil.scanFiles(saveStructure, this.serverLevel, this.fullDataFileHandler, null);
LOGGER.info("Started DHLevel for "+level+" with saves at "+saveStructure);
this.f3Message = new F3Screen.NestedMessage(this::f3Log);
this.chunkToLodBuilder = new ChunkToLodBuilder();
this.generatorEnabled = new AppliedConfigState<>(Config.Client.WorldGenerator.enableDistantGeneration);
this.worldGeneratorEnabledConfig = new AppliedConfigState<>(Config.Client.WorldGenerator.enableDistantGeneration);
LOGGER.info("Started DHLevel for "+serverLevel+" with saves at "+saveStructure);
}
//=======================//
// misc helper functions //
//=======================//
/** Returns what should be displayed in Minecraft's F3 debug menu */
private String[] f3Log()
{
@@ -89,6 +96,18 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
}
}
@Override
public void dumpRamUsage()
{
//TODO
}
//==============//
// tick methods //
//==============//
@Override
public void clientTick()
{
@@ -124,6 +143,55 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
@Override
public void serverTick() { this.chunkToLodBuilder.tick(); }
@Override
public void doWorldGen()
{
WorldGenState wgs = this.worldGenStateRef.get();
// if the world generator config changes, add/remove the world generator
if (this.worldGeneratorEnabledConfig.pollNewValue())
{
boolean shouldDoWorldGen = this.worldGeneratorEnabledConfig.get() && this.ClientRenderStateRef.get() != null;
if (shouldDoWorldGen && wgs == null)
{
// create the new world generator
WorldGenState newWgs = new WorldGenState(this);
if (!this.worldGenStateRef.compareAndSet(null, newWgs))
{
LOGGER.warn("Failed to start world gen due to concurrency");
newWgs.closeAsync(false);
}
}
else if (!shouldDoWorldGen && wgs != null)
{
// shut down the world generator
while (!this.worldGenStateRef.compareAndSet(wgs, null))
{
wgs = this.worldGenStateRef.get();
if (wgs == null)
{
return;
}
}
wgs.closeAsync(true).join(); //TODO: Make it async.
}
}
if (wgs != null)
{
// queue new world generation requests
wgs.chunkGenerator.preGeneratorTaskStart();
wgs.worldGenerationQueue.runCurrentGenTasksUntilBusy(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
}
}
//========//
// render //
//========//
public void startRenderer(IClientLevelWrapper clientLevel)
{
LOGGER.info("Starting renderer for "+this);
@@ -135,8 +203,8 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
}
else
{
this.generatorEnabled.pollNewValue();
if (this.generatorEnabled.get() && this.worldGenStateRef.get() == null)
this.worldGeneratorEnabledConfig.pollNewValue();
if (this.worldGeneratorEnabledConfig.get() && this.worldGenStateRef.get() == null)
{
WorldGenState worldGenState = new WorldGenState(this);
if (!this.worldGenStateRef.compareAndSet(null, worldGenState))
@@ -198,7 +266,13 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
}
}
@Override //FIXME
//================//
// level handling //
//================//
@Override //FIXME // why is this labeled "fixme"?
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block)
{
IClientLevelWrapper clientLevel = this.getClientLevelWrapper();
@@ -218,10 +292,21 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
return ClientRenderState == null ? null : ClientRenderState.clientLevel;
}
@Override
public IServerLevelWrapper getServerLevelWrapper() { return this.serverLevel; }
@Override
public ILevelWrapper getLevelWrapper() { return this.serverLevel; }
@Override
public int getMinY() { return this.serverLevel.getMinHeight(); }
//===============//
// data handling //
//===============//
@Override
public void updateChunkAsync(IChunkWrapper chunk)
{
@@ -241,30 +326,21 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
}
else
{
this.dataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
this.fullDataFileHandler.write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data);
}
}
@Override
public void dumpRamUsage()
{
//TODO
}
@Override
public int getMinY() { return this.serverLevel.getMinHeight(); }
@Override
public CompletableFuture<Void> saveAsync()
{
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
if (ClientRenderState != null)
{
return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.dataFileHandler.flushAndSave(), (voidA, voidB) -> null);
return ClientRenderState.renderSourceFileHandler.flushAndSave().thenCombine(this.fullDataFileHandler.flushAndSave(), (voidA, voidB) -> null);
}
else
{
return this.dataFileHandler.flushAndSave();
return this.fullDataFileHandler.flushAndSave();
}
}
@@ -304,53 +380,7 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
@Override
public void doWorldGen()
{
WorldGenState wgs = this.worldGenStateRef.get();
// if the world generator config changes, add/remove the world generator
if (this.generatorEnabled.pollNewValue())
{
boolean shouldDoWorldGen = this.generatorEnabled.get() && this.ClientRenderStateRef.get() != null;
if (shouldDoWorldGen && wgs == null)
{
// create the new world generator
WorldGenState newWgs = new WorldGenState(this);
if (!this.worldGenStateRef.compareAndSet(null, newWgs))
{
LOGGER.warn("Failed to start world gen due to concurrency");
newWgs.closeAsync(false);
}
}
else if (!shouldDoWorldGen && wgs != null)
{
// shut down the world generator
while (!this.worldGenStateRef.compareAndSet(wgs, null))
{
wgs = this.worldGenStateRef.get();
if (wgs == null)
{
return;
}
}
wgs.closeAsync(true).join(); //TODO: Make it async.
}
}
if (wgs != null)
{
// queue new world generation requests
wgs.chunkGenerator.preGeneratorTaskStart();
wgs.worldGenerationQueue.runCurrentGenTasksUntilBusy(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
}
}
@Override
public IServerLevelWrapper getServerLevelWrapper() { return this.serverLevel; }
@Override
public IFullDataSourceProvider getFileHandler() { return this.dataFileHandler; }
public IFullDataSourceProvider getFileHandler() { return this.fullDataFileHandler; }
@Override
public void clearRenderDataCache()
@@ -390,14 +420,14 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
this.chunkGenerator = worldGenerator;
this.worldGenerationQueue = new WorldGenerationQueue(this.chunkGenerator);
DhClientServerLevel.this.dataFileHandler.setGenerationQueue(this.worldGenerationQueue);
DhClientServerLevel.this.fullDataFileHandler.setGenerationQueue(this.worldGenerationQueue);
}
CompletableFuture<Void> closeAsync(boolean doInterrupt)
{
DhClientServerLevel.this.dataFileHandler.clearGenerationQueue();
DhClientServerLevel.this.fullDataFileHandler.clearGenerationQueue();
return this.worldGenerationQueue.startClosing(true, doInterrupt)
.exceptionally(ex ->
{
@@ -32,7 +32,7 @@ public class ClientRenderState
public ClientRenderState(DhClientServerLevel parent, IClientLevelWrapper clientLevel)
{
this.clientLevel = clientLevel;
this.renderSourceFileHandler = new RenderSourceFileHandler(parent.dataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.serverLevel));
this.renderSourceFileHandler = new RenderSourceFileHandler(parent.fullDataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.serverLevel));
this.quadtree = new LodQuadTree(parent, Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH,
MC_CLIENT.getPlayerBlockPos().x, MC_CLIENT.getPlayerBlockPos().z, this.renderSourceFileHandler);
@@ -44,13 +44,13 @@ public class ClientRenderState
public ClientRenderState(DhClientLevel parent, IClientLevelWrapper clientLevel)
{
this.clientLevel = clientLevel;
this.renderSourceFileHandler = new RenderSourceFileHandler(parent.dataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.level));
this.renderSourceFileHandler = new RenderSourceFileHandler(parent.fullDataFileHandler, parent, parent.saveStructure.getRenderCacheFolder(parent.clientLevel));
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);
FileScanUtil.scanFiles(parent.saveStructure, parent.clientLevel, null, this.renderSourceFileHandler);
this.renderer = new LodRenderer(renderBufferHandler);
}
@@ -97,6 +97,7 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
}
else
{
// TODO why is this called here?
this.levelObjMap.remove(wrapper).stopRenderer(); // Ignore resource warning. The level obj is referenced elsewhere.
}
}
@@ -121,7 +121,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
this.saveAndFlush().join();
for (DhClientLevel level : this.levels.values())
{
LOGGER.info("Unloading level " + level.level.getDimensionType().getDimensionName());
LOGGER.info("Unloading level " + level.clientLevel.getDimensionType().getDimensionName());
level.close();
}