Improve the casting around SharedApi.currentWorld

This commit is contained in:
James Seibel
2023-02-16 11:30:11 -06:00
parent 449aaf2d3a
commit d6397d6444
17 changed files with 374 additions and 245 deletions
@@ -18,6 +18,7 @@ import com.seibel.lod.core.util.*;
import com.seibel.lod.core.util.math.Vec3d;
import com.seibel.lod.core.util.math.Vec3f;
import com.seibel.lod.core.util.math.Vec3i;
import com.seibel.lod.core.world.AbstractDhWorld;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
@@ -166,18 +167,22 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
*/
private static DhApiResult<DhApiTerrainDataPoint[]> getTerrainDataColumnArray(IDhApiLevelWrapper levelWrapper, DhLodPos requestedColumnPos, Integer nullableBlockYPos)
{
if (SharedApi.currentWorld == null)
AbstractDhWorld currentWorld = SharedApi.getAbstractDhWorld();
if (currentWorld == null)
{
return DhApiResult.createFail("Unable to get terrain data before the world has loaded.");
}
if (!(levelWrapper instanceof ILevelWrapper coreLevelWrapper))
if (!ILevelWrapper.class.isInstance(levelWrapper))
{
// custom level wrappers aren't supported,
// the API user must get a level wrapper from our code somewhere
return DhApiResult.createFail("Unsupported [" + IDhApiLevelWrapper.class.getSimpleName() + "] implementation, only the core class [" + IDhLevel.class.getSimpleName() + "] is a valid parameter.");
return DhApiResult.createFail("Unsupported ["+IDhApiLevelWrapper.class.getSimpleName()+"] implementation, only the core class ["+IDhLevel.class.getSimpleName()+"] is a valid parameter.");
}
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
IDhLevel level = SharedApi.currentWorld.getLevel(coreLevelWrapper);
IDhLevel level = currentWorld.getLevel(coreLevelWrapper);
if (level == null)
{
return DhApiResult.createFail("Unable to get terrain data before the world has loaded.");
@@ -101,7 +101,7 @@ public class ClientApi
LOGGER.info("Client on ClientOnly mode connecting.");
}
SharedApi.currentWorld = new DhClientWorld();
SharedApi.setDhWorld(new DhClientWorld());
}
public void onClientOnlyDisconnected()
@@ -111,15 +111,15 @@ public class ClientApi
LOGGER.info("Client on ClientOnly mode disconnecting.");
}
SharedApi.currentWorld.close();
SharedApi.currentWorld = null;
SharedApi.getAbstractDhWorld().close();
SharedApi.setDhWorld(null);
}
public void clientChunkLoadEvent(IChunkWrapper chunk, IClientLevelWrapper level)
{
if (SharedApi.getEnvironment() == EWorldEnvironment.Client_Only)
{
IDhLevel dhLevel = SharedApi.currentWorld.getLevel(level);
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
if (dhLevel != null)
{
dhLevel.updateChunk(chunk);
@@ -145,9 +145,10 @@ public class ClientApi
LOGGER.info("Client level "+level+" unloading.");
}
if (SharedApi.currentWorld != null)
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null)
{
SharedApi.currentWorld.unloadLevel(level);
world.unloadLevel(level);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level));
}
}
@@ -159,9 +160,10 @@ public class ClientApi
LOGGER.info("Client level "+level+" loading.");
}
if (SharedApi.currentWorld != null)
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world != null)
{
SharedApi.currentWorld.getOrLoadLevel(level);
world.getOrLoadLevel(level);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level));
}
}
@@ -208,9 +210,10 @@ public class ClientApi
ConfigBasedLogger.updateAll();
ConfigBasedSpamLogger.updateAll(doFlush);
if (SharedApi.currentWorld instanceof IDhClientWorld)
IDhClientWorld clientWorld = SharedApi.getIDhClientWorld();
if (clientWorld != null)
{
((IDhClientWorld) SharedApi.currentWorld).clientTick();
clientWorld.clientTick();
}
profiler.pop();
}
@@ -246,8 +249,8 @@ public class ClientApi
//FIXME: Improve class hierarchy of DhWorld, IClientWorld, IServerWorld to fix all this hard casting
// (also in RenderUtil)
AbstractDhWorld dhWorld = SharedApi.currentWorld;
IDhClientLevel level = (IDhClientLevel) dhWorld.getOrLoadLevel(levelWrapper);
IDhClientWorld dhClientWorld = SharedApi.getIDhClientWorld();
IDhClientLevel level = dhClientWorld.getOrLoadClientLevel(levelWrapper);
if (prefLoggerEnabled)
{
@@ -24,19 +24,16 @@ import com.seibel.lod.api.methods.events.abstractEvents.DhApiLevelSaveEvent;
import com.seibel.lod.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
import com.seibel.lod.core.DependencyInjection.ApiEventInjector;
import com.seibel.lod.core.level.IDhLevel;
import com.seibel.lod.core.world.AbstractDhWorld;
import com.seibel.lod.core.world.DhClientServerWorld;
import com.seibel.lod.core.world.DhServerWorld;
import com.seibel.lod.core.world.IDhServerWorld;
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
import com.seibel.lod.core.logging.DhLoggerBuilder;
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IServerLevelWrapper;
import org.apache.logging.log4j.Logger;
import java.lang.invoke.MethodHandles;
/**
* This holds the methods that should be called by the host mod loader (Fabric,
* Forge, etc.). Specifically server events.
@@ -65,9 +62,9 @@ public class ServerApi
public void serverTickEvent()
{
if (SharedApi.currentWorld instanceof IDhServerWorld)
IDhServerWorld serverWorld = SharedApi.getIDhServerWorld();
if (serverWorld != null)
{
IDhServerWorld serverWorld = (IDhServerWorld) SharedApi.currentWorld;
serverWorld.serverTick();
this.lastWorldGenTickDelta--;
if (this.lastWorldGenTickDelta <= 0)
@@ -89,25 +86,18 @@ public class ServerApi
LOGGER.info("Server World loading with (dedicated?:{})", isDedicatedEnvironment);
}
if (isDedicatedEnvironment)
{
SharedApi.currentWorld = new DhServerWorld();
}
else
{
SharedApi.currentWorld = new DhClientServerWorld();
}
SharedApi.setDhWorld(isDedicatedEnvironment ? new DhServerWorld() : new DhClientServerWorld());
}
public void serverUnloadEvent()
{
if (ENABLE_EVENT_LOGGING)
{
LOGGER.info("Server World "+SharedApi.currentWorld+" unloading");
LOGGER.info("Server World "+SharedApi.getAbstractDhWorld()+" unloading");
}
SharedApi.currentWorld.close();
SharedApi.currentWorld = null;
SharedApi.getAbstractDhWorld().close();
SharedApi.setDhWorld(null);
}
public void serverLevelLoadEvent(IServerLevelWrapper level)
@@ -117,9 +107,10 @@ public class ServerApi
LOGGER.info("Server Level {} loading", level);
}
if (SharedApi.currentWorld != null)
AbstractDhWorld serverWorld = SharedApi.getAbstractDhWorld();
if (serverWorld != null)
{
SharedApi.currentWorld.getOrLoadLevel(level);
serverWorld.getOrLoadLevel(level);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level));
}
}
@@ -130,9 +121,10 @@ public class ServerApi
LOGGER.info("Server Level {} unloading", level);
}
if (SharedApi.currentWorld != null)
AbstractDhWorld serverWorld = SharedApi.getAbstractDhWorld();
if (serverWorld != null)
{
SharedApi.currentWorld.unloadLevel(level);
serverWorld.unloadLevel(level);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level));
}
}
@@ -142,14 +134,15 @@ public class ServerApi
{
if (ENABLE_EVENT_LOGGING)
{
LOGGER.info("Server world {} saving", SharedApi.currentWorld);
LOGGER.info("Server world "+SharedApi.getAbstractDhWorld()+" saving");
}
if (SharedApi.currentWorld instanceof IDhServerWorld)
AbstractDhWorld serverWorld = SharedApi.getAbstractDhWorld();
if (serverWorld != null)
{
SharedApi.currentWorld.saveAndFlush();
serverWorld.saveAndFlush();
for (IDhLevel level : SharedApi.currentWorld.getAllLoadedLevels())
for (IDhLevel level : serverWorld.getAllLoadedLevels())
{
ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelSaveEvent.class, new DhApiLevelSaveEvent.EventParam(level.getLevelWrapper()));
}
@@ -158,7 +151,7 @@ public class ServerApi
public void serverChunkLoadEvent(IChunkWrapper chunk, ILevelWrapper level)
{
IDhLevel dhLevel = SharedApi.currentWorld.getLevel(level);
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
if (dhLevel != null)
{
dhLevel.updateChunk(chunk);
@@ -166,7 +159,7 @@ public class ServerApi
}
public void serverChunkSaveEvent(IChunkWrapper chunk, ILevelWrapper level)
{
IDhLevel dhLevel = SharedApi.currentWorld.getLevel(level);
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
if (dhLevel != null)
{
dhLevel.updateChunk(chunk);
@@ -1,14 +1,14 @@
package com.seibel.lod.core.api.internal;
import com.seibel.lod.core.Initializer;
import com.seibel.lod.core.world.EWorldEnvironment;
import com.seibel.lod.core.world.AbstractDhWorld;
import com.seibel.lod.core.world.*;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
public class SharedApi
{
public static IMinecraftSharedWrapper MC;
public static AbstractDhWorld currentWorld;
private static AbstractDhWorld currentWorld;
@@ -18,4 +18,17 @@ public class SharedApi
public static EWorldEnvironment getEnvironment() { return (currentWorld == null) ? null : currentWorld.environment; }
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} */
public static IDhServerWorld getIDhServerWorld() { return (currentWorld != null && IDhServerWorld.class.isInstance(currentWorld)) ? (IDhServerWorld) currentWorld : null; }
}
@@ -101,7 +101,7 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
return;
}
if (renderState.quadtree.blockViewDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
if (renderState.quadtree.blockRenderDistance != Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
{
if (!this.renderStateRef.compareAndSet(renderState, null))
{
@@ -4,6 +4,7 @@ import com.seibel.lod.api.interfaces.render.IDhApiRenderProxy;
import com.seibel.lod.api.objects.DhApiResult;
import com.seibel.lod.core.api.internal.SharedApi;
import com.seibel.lod.core.level.IDhLevel;
import com.seibel.lod.core.world.AbstractDhWorld;
/**
* Used to interact with Distant Horizons' rendering systems.
@@ -24,14 +25,15 @@ public class DhApiRenderProxy implements IDhApiRenderProxy
public DhApiResult<Boolean> clearRenderDataCache()
{
// make sure this is a valid time to run the method
if (SharedApi.currentWorld == null)
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world == null)
{
return DhApiResult.createFail("No world loaded");
}
// clear the render caches for each level
Iterable<? extends IDhLevel> loadedLevels = SharedApi.currentWorld.getAllLoadedLevels();
Iterable<? extends IDhLevel> loadedLevels = world.getAllLoadedLevels();
for (IDhLevel level : loadedLevels)
{
if (level != null)
@@ -50,7 +50,7 @@ public class LodQuadTree implements AutoCloseable
private final MovableGridRingList<LodRenderSection>[] renderSectionRingLists;
public final int blockViewDistance;
public final int blockRenderDistance;
private final ILodRenderSourceProvider renderSourceProvider;
private final IDhClientLevel level; //FIXME: Proper hierarchy to remove this reference!
@@ -72,7 +72,7 @@ public class LodQuadTree implements AutoCloseable
DetailDistanceUtil.updateSettings(); //TODO: Move this to somewhere else
this.level = level;
this.renderSourceProvider = provider;
this.blockViewDistance = viewDistance;
this.blockRenderDistance = viewDistance;
@@ -179,17 +179,23 @@ public class RenderUtil
int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
float nearClipPlane;
if (Config.Client.Advanced.lodOnlyMode.get()) {
if (Config.Client.Advanced.lodOnlyMode.get())
{
nearClipPlane = 0.1f;
} else if (Config.Client.Graphics.AdvancedGraphics.useExtendedNearClipPlane.get()) {
}
else if (Config.Client.Graphics.AdvancedGraphics.useExtendedNearClipPlane.get())
{
nearClipPlane = Math.min(vanillaBlockRenderedDistance - LodUtil.CHUNK_WIDTH, (float) 8 * LodUtil.CHUNK_WIDTH); // allow a max near clip plane of 8 chunks
} else {
}
else
{
nearClipPlane = 16f;
}
// modify the based on the player's FOV
double fov = MC_RENDER.getFov(partialTicks);
double aspectRatio = (double) MC_RENDER.getScreenWidth() / MC_RENDER.getScreenHeight();
return (float) (nearClipPlane
/ Math.sqrt(1d + MathUtil.pow2(Math.tan(fov / 180d * Math.PI / 2d))
* (MathUtil.pow2(aspectRatio) + 1d)));
@@ -204,23 +210,26 @@ public class RenderUtil
public static boolean shouldLodsRender(ILevelWrapper levelWrapper)
{
if (!MC.playerExists())
{
return false;
}
if (levelWrapper == null)
{
return false;
}
AbstractDhWorld dhWorld = SharedApi.currentWorld;
if (dhWorld == null)
IDhClientWorld clientWorld = SharedApi.getIDhClientWorld();
if (clientWorld == null)
{
return false;
}
if (!(SharedApi.currentWorld instanceof IDhClientWorld))
return false; // don't attempt to render server worlds
//FIXME: Improve class hierarchy of DhWorld, IClientWorld, IServerWorld to fix all this hard casting
// (also in ClientApi)
IDhClientLevel level = (IDhClientLevel) dhWorld.getOrLoadLevel(levelWrapper);
IDhClientLevel level = clientWorld.getOrLoadClientLevel(levelWrapper);
if (level == null)
{
return false; //Level is not ready yet.
}
if (MC_RENDER.playerHasBlindnessEffect())
{
@@ -231,7 +240,9 @@ public class RenderUtil
}
if (MC_RENDER.getLightmapWrapper() == null)
{
return false;
}
return true;
}
@@ -16,24 +16,19 @@ import java.util.concurrent.CompletableFuture;
* Represents an entire world (aka server) and
* contains every level in that world.
*/
public abstract class AbstractDhWorld implements Closeable
public abstract class AbstractDhWorld implements IDhWorld, Closeable
{
protected static final Logger LOGGER = DhLoggerBuilder.getLogger();
public final EWorldEnvironment environment;
protected AbstractDhWorld(EWorldEnvironment environment) {
this.environment = environment;
}
public abstract IDhLevel getOrLoadLevel(ILevelWrapper wrapper);
public abstract IDhLevel getLevel(ILevelWrapper wrapper);
public abstract Iterable<? extends IDhLevel> getAllLoadedLevels();
public abstract void unloadLevel(ILevelWrapper wrapper);
public abstract CompletableFuture<Void> saveAndFlush();
@Override
public abstract void close();
protected AbstractDhWorld(EWorldEnvironment environment) { this.environment = environment; }
// remove the "throws IOException"
@Override
public abstract void close();
}
@@ -38,12 +38,12 @@ public class DhApiWorldProxy implements IDhApiWorldProxy
@Override
public boolean worldLoaded() { return SharedApi.currentWorld != null; }
public boolean worldLoaded() { return SharedApi.getAbstractDhWorld() != null; }
@Override
public IDhApiLevelWrapper getSinglePlayerLevel()
{
if (SharedApi.currentWorld == null)
if (SharedApi.getAbstractDhWorld() == null)
{
throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
}
@@ -63,14 +63,14 @@ public class DhApiWorldProxy implements IDhApiWorldProxy
@Override
public Iterable<IDhApiLevelWrapper> getAllLoadedLevelWrappers()
{
if (SharedApi.currentWorld == null)
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world == null)
{
throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
}
ArrayList<IDhApiLevelWrapper> returnList = new ArrayList<>();
for (IDhLevel dhLevel : SharedApi.currentWorld.getAllLoadedLevels())
for (IDhLevel dhLevel : world.getAllLoadedLevels())
{
returnList.add(dhLevel.getLevelWrapper());
}
@@ -80,14 +80,14 @@ public class DhApiWorldProxy implements IDhApiWorldProxy
@Override
public Iterable<IDhApiLevelWrapper> getAllLoadedLevelsForDimensionType(IDhApiDimensionTypeWrapper dimensionTypeWrapper)
{
if (SharedApi.currentWorld == null)
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world == null)
{
throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
}
ArrayList<IDhApiLevelWrapper> returnList = new ArrayList<>();
for (IDhLevel dhLevel : SharedApi.currentWorld.getAllLoadedLevels())
for (IDhLevel dhLevel : world.getAllLoadedLevels())
{
ILevelWrapper levelWrapper = dhLevel.getLevelWrapper();
if (levelWrapper.getDimensionType().equals(dimensionTypeWrapper))
@@ -101,16 +101,16 @@ public class DhApiWorldProxy implements IDhApiWorldProxy
@Override
public Iterable<IDhApiLevelWrapper> getAllLoadedLevelsWithDimensionNameLike(String dimensionName)
{
if (SharedApi.currentWorld == null)
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
if (world == null)
{
throw new IllegalStateException(NO_WORLD_EXCEPTION_STRING);
}
String soughtDimName = dimensionName.toLowerCase();
ArrayList<IDhApiLevelWrapper> returnList = new ArrayList<>();
for (IDhLevel dhLevel : SharedApi.currentWorld.getAllLoadedLevels())
for (IDhLevel dhLevel : world.getAllLoadedLevels())
{
ILevelWrapper levelWrapper = dhLevel.getLevelWrapper();
String levelDimName = levelWrapper.getDimensionType().getDimensionName().toLowerCase();
@@ -21,20 +21,28 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
private final HashMap<ILevelWrapper, DhClientServerLevel> levelObjMap;
private final HashSet<DhClientServerLevel> dhLevels;
public final LocalSaveStructure saveStructure;
public ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHTickerThread", 2);
public EventLoop eventLoop = new EventLoop(dhTickerThread, this::_clientTick); //TODO: Rate-limit the loop
public F3Screen.DynamicMessage f3Msg;
public DhClientServerWorld() {
public EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick); //TODO: Rate-limit the loop
public F3Screen.DynamicMessage f3Message;
public DhClientServerWorld()
{
super(EWorldEnvironment.Client_Server);
saveStructure = new LocalSaveStructure();
levelObjMap = new HashMap<>();
dhLevels = new HashSet<>();
LOGGER.info("Started DhWorld of type {}", environment);
f3Msg = new F3Screen.DynamicMessage(() ->
LodUtil.formatLog("{} World with {} levels", environment, dhLevels.size()));
this.saveStructure = new LocalSaveStructure();
this.levelObjMap = new HashMap<>();
this.dhLevels = new HashSet<>();
LOGGER.info("Started DhWorld of type "+this.environment);
this.f3Message = new F3Screen.DynamicMessage(() -> LodUtil.formatLog(this.environment+" World with "+this.dhLevels.size()+" levels"));
}
@Override
public DhClientServerLevel getOrLoadLevel(ILevelWrapper wrapper)
{
@@ -56,9 +64,13 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
IClientLevelWrapper clientSide = (IClientLevelWrapper) levelWrapper;
IServerLevelWrapper serverSide = clientSide.tryGetServerSideWrapper();
LodUtil.assertTrue(serverSide != null);
DhClientServerLevel level = this.levelObjMap.get(serverSide);
if (level == null)
{
return null;
}
level.startRenderer(clientSide);
return level;
});
@@ -90,38 +102,42 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
}
}
private void _clientTick() {
private void _clientTick()
{
//LOGGER.info("Client world tick with {} levels", levels.size());
dhLevels.forEach(DhClientServerLevel::clientTick);
this.dhLevels.forEach(DhClientServerLevel::clientTick);
}
public void clientTick() {
public void clientTick()
{
//LOGGER.info("Client world tick");
eventLoop.tick();
this.eventLoop.tick();
}
public void serverTick() {
dhLevels.forEach(DhClientServerLevel::serverTick);
}
public void serverTick() { this.dhLevels.forEach(DhClientServerLevel::serverTick); }
public void doWorldGen() {
dhLevels.forEach(DhClientServerLevel::doWorldGen);
}
public void doWorldGen() { this.dhLevels.forEach(DhClientServerLevel::doWorldGen); }
@Override
public CompletableFuture<Void> saveAndFlush() {
return CompletableFuture.allOf(dhLevels.stream().map(DhClientServerLevel::save).toArray(CompletableFuture[]::new));
}
public CompletableFuture<Void> saveAndFlush()
{
return CompletableFuture.allOf(this.dhLevels.stream().map(DhClientServerLevel::save).toArray(CompletableFuture[]::new));
}
@Override
public void close() {
saveAndFlush().join();
for (DhClientServerLevel level : dhLevels) {
LOGGER.info("Unloading level " + level.serverLevel.getDimensionType().getDimensionName());
level.close();
}
levelObjMap.clear();
eventLoop.close();
LOGGER.info("Closed DhWorld of type {}", environment);
}
public void close()
{
this.saveAndFlush().join();
for (DhClientServerLevel level : this.dhLevels)
{
LOGGER.info("Unloading level " + level.serverLevel.getDimensionType().getDimensionName());
level.close();
}
this.levelObjMap.clear();
this.eventLoop.close();
LOGGER.info("Closed DhWorld of type "+this.environment);
}
}
@@ -20,80 +20,111 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
{
private final HashMap<IClientLevelWrapper, DhClientLevel> levels;
public final ClientOnlySaveStructure saveStructure;
public ExecutorService dhTickerThread = LodUtil.makeSingleThreadPool("DHTickerThread", 2);
public EventLoop eventLoop = new EventLoop(dhTickerThread, this::_clientTick);
public DhClientWorld() {
super(EWorldEnvironment.Client_Only);
saveStructure = new ClientOnlySaveStructure();
levels = new HashMap<>();
LOGGER.info("Started DhWorld of type {}", environment);
}
public EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick);
public DhClientWorld()
{
super(EWorldEnvironment.Client_Only);
this.saveStructure = new ClientOnlySaveStructure();
this.levels = new HashMap<>();
LOGGER.info("Started DhWorld of type "+this.environment);
}
@Override
public DhClientLevel getOrLoadLevel(ILevelWrapper wrapper) {
if (!(wrapper instanceof IClientLevelWrapper)) return null;
public DhClientLevel getOrLoadLevel(ILevelWrapper wrapper)
{
if (!(wrapper instanceof IClientLevelWrapper))
{
return null;
}
return levels.computeIfAbsent((IClientLevelWrapper) wrapper, (w) -> {
File level = saveStructure.tryGetOrCreateLevelFolder(wrapper);
if (level == null) return null;
return new DhClientLevel(saveStructure, w);
return this.levels.computeIfAbsent((IClientLevelWrapper) wrapper, (clientLevelWrapper) ->
{
File level = this.saveStructure.tryGetOrCreateLevelFolder(wrapper);
if (level == null)
{
return null;
}
return new DhClientLevel(this.saveStructure, clientLevelWrapper);
});
}
@Override
public DhClientLevel getLevel(ILevelWrapper wrapper) {
if (!(wrapper instanceof IClientLevelWrapper)) return null;
return levels.get(wrapper);
public DhClientLevel getLevel(ILevelWrapper wrapper)
{
if (!(wrapper instanceof IClientLevelWrapper))
{
return null;
}
return this.levels.get(wrapper);
}
@Override
public Iterable<? extends IDhLevel> getAllLoadedLevels()
{
return levels.values();
}
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.levels.values(); }
@Override
public void unloadLevel(ILevelWrapper wrapper) {
if (!(wrapper instanceof IClientLevelWrapper)) return;
if (levels.containsKey(wrapper)) {
LOGGER.info("Unloading level {} ", levels.get(wrapper));
levels.remove(wrapper).close();
public void unloadLevel(ILevelWrapper wrapper)
{
if (!(wrapper instanceof IClientLevelWrapper))
{
return;
}
if (this.levels.containsKey(wrapper))
{
LOGGER.info("Unloading level "+this.levels.get(wrapper));
this.levels.remove(wrapper).close();
}
}
private void _clientTick() {
int newViewDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH;
Iterator<DhClientLevel> iterator = levels.values().iterator();
while (iterator.hasNext()) {
DhClientLevel level = iterator.next();
if (level.tree.blockViewDistance != newViewDistance) {
level.close();
iterator.remove();
}
}
DetailDistanceUtil.updateSettings();
levels.values().forEach(DhClientLevel::clientTick);
}
private void _clientTick()
{
int newBlockRenderDistance = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH;
Iterator<DhClientLevel> iterator = this.levels.values().iterator();
while (iterator.hasNext())
{
DhClientLevel level = iterator.next();
if (level.tree.blockRenderDistance != newBlockRenderDistance)
{
level.close();
iterator.remove();
}
}
DetailDistanceUtil.updateSettings();
this.levels.values().forEach(DhClientLevel::clientTick);
}
public void clientTick() {
eventLoop.tick();
public void clientTick() { this.eventLoop.tick(); }
@Override
public CompletableFuture<Void> saveAndFlush()
{
return CompletableFuture.allOf(this.levels.values().stream().map(DhClientLevel::save).toArray(CompletableFuture[]::new));
}
@Override
public CompletableFuture<Void> saveAndFlush() {
return CompletableFuture.allOf(levels.values().stream().map(DhClientLevel::save).toArray(CompletableFuture[]::new));
}
@Override
public void close() {
saveAndFlush().join();
for (DhClientLevel level : levels.values()) {
public void close()
{
this.saveAndFlush().join();
for (DhClientLevel level : this.levels.values())
{
LOGGER.info("Unloading level " + level.level.getDimensionType().getDimensionName());
level.close();
}
levels.clear();
eventLoop.close();
LOGGER.info("Closed DhWorld of type {}", environment);
this.levels.clear();
this.eventLoop.close();
LOGGER.info("Closed DhWorld of type "+this.environment);
}
}
@@ -3,6 +3,7 @@ package com.seibel.lod.core.world;
import com.seibel.lod.core.level.DhServerLevel;
import com.seibel.lod.core.level.IDhLevel;
import com.seibel.lod.core.file.structure.LocalSaveStructure;
import com.seibel.lod.core.level.IDhServerLevel;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IServerLevelWrapper;
@@ -13,71 +14,91 @@ import java.util.concurrent.CompletableFuture;
public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld
{
private final HashMap<IServerLevelWrapper, DhServerLevel> levels;
public final LocalSaveStructure saveStructure;
public DhServerWorld() {
super(EWorldEnvironment.Server_Only);
saveStructure = new LocalSaveStructure();
levels = new HashMap<>();
LOGGER.info("Started DhWorld of type {}", environment);
}
@Override
public DhServerLevel getOrLoadLevel(ILevelWrapper wrapper) {
if (!(wrapper instanceof IServerLevelWrapper)) return null;
return levels.computeIfAbsent((IServerLevelWrapper) wrapper, (w) -> {
File levelFile = saveStructure.tryGetOrCreateLevelFolder(wrapper);
LodUtil.assertTrue(levelFile != null);
return new DhServerLevel(saveStructure, w);
});
}
@Override
public DhServerLevel getLevel(ILevelWrapper wrapper) {
if (!(wrapper instanceof IServerLevelWrapper)) return null;
return levels.get(wrapper);
}
@Override
public Iterable<? extends IDhLevel> getAllLoadedLevels()
{
return levels.values();
}
@Override
public void unloadLevel(ILevelWrapper wrapper) {
if (!(wrapper instanceof IServerLevelWrapper)) return;
if (levels.containsKey(wrapper)) {
LOGGER.info("Unloading level {} ", levels.get(wrapper));
levels.remove(wrapper).close();
}
}
public void serverTick() {
levels.values().forEach(DhServerLevel::serverTick);
}
public void doWorldGen() {
levels.values().forEach(DhServerLevel::doWorldGen);
}
@Override
public CompletableFuture<Void> saveAndFlush() {
return CompletableFuture.allOf(levels.values().stream().map(DhServerLevel::save).toArray(CompletableFuture[]::new));
}
@Override
public void close() {
for (DhServerLevel level : levels.values()) {
LOGGER.info("Unloading level " + level.level.getDimensionType().getDimensionName());
level.close();
}
levels.clear();
LOGGER.info("Closed DhWorld of type {}", environment);
}
private final HashMap<IServerLevelWrapper, DhServerLevel> levels;
public final LocalSaveStructure saveStructure;
public DhServerWorld()
{
super(EWorldEnvironment.Server_Only);
this.saveStructure = new LocalSaveStructure();
this.levels = new HashMap<>();
LOGGER.info("Started "+DhServerWorld.class.getSimpleName()+" of type "+this.environment);
}
@Override
public DhServerLevel getOrLoadLevel(ILevelWrapper wrapper)
{
if (!(wrapper instanceof IServerLevelWrapper))
{
return null;
}
return this.levels.computeIfAbsent((IServerLevelWrapper) wrapper, (w) ->
{
File levelFile = this.saveStructure.tryGetOrCreateLevelFolder(wrapper);
LodUtil.assertTrue(levelFile != null);
return new DhServerLevel(this.saveStructure, w);
});
}
@Override
public DhServerLevel getLevel(ILevelWrapper wrapper)
{
if (!(wrapper instanceof IServerLevelWrapper))
{
return null;
}
return this.levels.get(wrapper);
}
@Override
public Iterable<? extends IDhLevel> getAllLoadedLevels() { return this.levels.values(); }
@Override
public void unloadLevel(ILevelWrapper wrapper)
{
if (!(wrapper instanceof IServerLevelWrapper))
{
return;
}
if (this.levels.containsKey(wrapper))
{
LOGGER.info("Unloading level {} ", this.levels.get(wrapper));
this.levels.remove(wrapper).close();
}
}
public void serverTick() { this.levels.values().forEach(DhServerLevel::serverTick); }
public void doWorldGen() { this.levels.values().forEach(DhServerLevel::doWorldGen); }
@Override
public CompletableFuture<Void> saveAndFlush()
{
return CompletableFuture.allOf(this.levels.values().stream().map(DhServerLevel::save).toArray(CompletableFuture[]::new));
}
@Override
public void close()
{
for (DhServerLevel level : this.levels.values())
{
LOGGER.info("Unloading level " + level.level.getDimensionType().getDimensionName());
level.close();
}
this.levels.clear();
LOGGER.info("Closed DhWorld of type "+this.environment);
}
}
@@ -1,5 +1,10 @@
package com.seibel.lod.core.world;
/**
* Client_Only,
* Client_Server,
* Server_Only
*/
public enum EWorldEnvironment
{
Client_Only,
@@ -1,6 +1,13 @@
package com.seibel.lod.core.world;
public interface IDhClientWorld
import com.seibel.lod.core.level.IDhClientLevel;
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
public interface IDhClientWorld extends IDhWorld
{
void clientTick();
default IDhClientLevel getOrLoadClientLevel(ILevelWrapper levelWrapper) { return (IDhClientLevel) this.getOrLoadLevel(levelWrapper); }
}
@@ -1,7 +1,15 @@
package com.seibel.lod.core.world;
public interface IDhServerWorld
import com.seibel.lod.core.level.IDhServerLevel;
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
/** Used both for dedicated server and singleplayer worlds */
public interface IDhServerWorld extends IDhWorld
{
void serverTick();
void doWorldGen();
default IDhServerLevel getOrLoadServerLevel(ILevelWrapper levelWrapper) { return (IDhServerLevel) this.getOrLoadLevel(levelWrapper); }
}
@@ -0,0 +1,19 @@
package com.seibel.lod.core.world;
import com.seibel.lod.core.level.IDhLevel;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
import java.util.concurrent.CompletableFuture;
public interface IDhWorld
{
IDhLevel getOrLoadLevel(ILevelWrapper levelWrapper);
IDhLevel getLevel(ILevelWrapper wrapper);
Iterable<? extends IDhLevel> getAllLoadedLevels();
void unloadLevel(ILevelWrapper levelWrapper);
CompletableFuture<Void> saveAndFlush();
}