Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core
This commit is contained in:
@@ -4,7 +4,7 @@ This repo is for the Distant Horizons mod.
|
||||
The purpose of this submodule is to isolate code that isn't tied to a specific version of minecraft. This prevents us from having duplicate code; reducing errors and potentially helping us port to different versions faster and easier.
|
||||
|
||||
Check out the mod's main GitLab page here:
|
||||
https://gitlab.com/jeseibel/minecraft-lod-mod
|
||||
https://gitlab.com/jeseibel/distant-horizons
|
||||
|
||||
## source code installation
|
||||
|
||||
|
||||
+19
-8
@@ -26,7 +26,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* @param <T> The data type of this config.
|
||||
* @author James Seibel
|
||||
* @version 2022-9-15
|
||||
* @version 2023-12-7
|
||||
* @since API 1.0.0
|
||||
*/
|
||||
public interface IDhApiConfigValue<T>
|
||||
@@ -43,25 +43,36 @@ public interface IDhApiConfigValue<T>
|
||||
* This is the value stored in the config file.
|
||||
*/
|
||||
T getTrueValue();
|
||||
/*
|
||||
/**
|
||||
* Returns the value of the config if it was set by the API.
|
||||
* Returns null if the config wasn't set by the API.
|
||||
* Returns null if the config hasn't been set by the API.
|
||||
*
|
||||
* @since API 1.1.0
|
||||
*/
|
||||
//T getApiValue(); // not currently implemented
|
||||
T getApiValue();
|
||||
|
||||
/**
|
||||
* Sets the config's value. <br>
|
||||
* If the newValue is set to null then the config
|
||||
* will revert to using the True Value.<br>
|
||||
* will revert to using the True Value
|
||||
* (IE the value visible in the config menu).<br>
|
||||
* If the config cannot be set via the API this method will return false. <br><br>
|
||||
*
|
||||
* To unset the config's value pass in Null. <br>
|
||||
*
|
||||
* @return true if the value was set, false otherwise.
|
||||
*/
|
||||
boolean setValue(T newValue);
|
||||
|
||||
/** Returns true if this config can be set via the API, false otherwise. */
|
||||
/**
|
||||
* Un-sets the config's API value. <br>
|
||||
* After this method is called this config will
|
||||
* use the value set in the config menu.
|
||||
*
|
||||
* @return true if the value was set, false otherwise.
|
||||
* @since API 1.1.0
|
||||
*/
|
||||
boolean clearValue();
|
||||
|
||||
/** @return true if this config can be set via the API, false otherwise. */
|
||||
boolean getCanBeOverrodeByApi();
|
||||
|
||||
/** Returns the default value for this config. */
|
||||
|
||||
@@ -87,6 +87,8 @@ public class DhApiConfigValue<coreType, apiType> implements IDhApiConfigValue<ap
|
||||
}
|
||||
}
|
||||
|
||||
public boolean clearValue() { return this.setValue(null); }
|
||||
|
||||
public boolean getCanBeOverrodeByApi() { return this.configEntry.getAllowApiOverride(); }
|
||||
|
||||
public apiType getDefaultValue() { return this.configConverter.convertToApiType(this.configEntry.getDefaultValue()); }
|
||||
|
||||
@@ -110,9 +110,11 @@ public class ClientApi
|
||||
/**
|
||||
* May be fired slightly before or after the associated
|
||||
* {@link ClientApi#clientLevelLoadEvent(IClientLevelWrapper)} event
|
||||
* depending on how the host mod loader functions.
|
||||
* depending on how the host mod loader functions. <br><br>
|
||||
*
|
||||
* Synchronized shouldn't be necessary, but is present to match {@see onClientOnlyDisconnected} and prevent any unforeseen issues.
|
||||
*/
|
||||
public void onClientOnlyConnected()
|
||||
public synchronized void onClientOnlyConnected()
|
||||
{
|
||||
// only continue if the client is connected to a different server
|
||||
if (MC.clientConnectedToDedicatedServer())
|
||||
@@ -134,7 +136,8 @@ public class ClientApi
|
||||
}
|
||||
}
|
||||
|
||||
public void onClientOnlyDisconnected()
|
||||
/** Synchronized to prevent a rare issue where multiple disconnect events are triggered on top of each other. */
|
||||
public synchronized void onClientOnlyDisconnected()
|
||||
{
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class LodDataBuilder
|
||||
|
||||
|
||||
ChunkSizedFullDataAccessor chunkData = new ChunkSizedFullDataAccessor(chunkWrapper.getChunkPos());
|
||||
int minBuildHeight = chunkWrapper.getMinFilledHeight();
|
||||
int minBuildHeight = chunkWrapper.getMinNonEmptyHeight();
|
||||
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
||||
* if this is too high it may cause issues when moving,
|
||||
* but if it is too low the generator threads won't have enough tasks to work on
|
||||
*/
|
||||
private static final int MAX_QUEUED_TASKS = 3;
|
||||
private static final int MAX_QUEUED_TASKS_PER_THREAD = 3;
|
||||
|
||||
public AbstractBatchGenerationEnvironmentWrapper generationEnvironment;
|
||||
public IDhLevel targetDhLevel;
|
||||
@@ -150,7 +150,9 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
||||
@Override
|
||||
public boolean isBusy()
|
||||
{
|
||||
return this.generationEnvironment.getEventCount() > Math.max(Config.Client.Advanced.MultiThreading.numberOfWorldGenerationThreads.get().intValue(), 1) * MAX_QUEUED_TASKS;
|
||||
int worldGenThreadCount = Math.max(Config.Client.Advanced.MultiThreading.numberOfWorldGenerationThreads.get(), 1);
|
||||
int maxWorldGenTaskCount = worldGenThreadCount * MAX_QUEUED_TASKS_PER_THREAD;
|
||||
return this.generationEnvironment.getEventCount() > maxWorldGenTaskCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -140,13 +140,16 @@ public class DhLightingEngine
|
||||
// if the dimension has skylights
|
||||
if (maxSkyLight > 0)
|
||||
{
|
||||
int maxY = chunk.getMaxNonEmptyHeight();
|
||||
int minY = chunk.getMinBuildHeight();
|
||||
|
||||
// get the adjacent chunk's sky lights
|
||||
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) // relative block pos
|
||||
{
|
||||
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||
{
|
||||
// set each pos' sky light all the way down until a opaque block is hit
|
||||
for (int y = chunk.getMaxBuildHeight(); y >= chunk.getMinBuildHeight(); y--)
|
||||
for (int y = maxY; y >= minY; y--)
|
||||
{
|
||||
IBlockStateWrapper block = chunk.getBlockState(relX, y, relZ);
|
||||
if (block != null && block.getOpacity() != IBlockStateWrapper.FULLY_TRANSPARENT)
|
||||
@@ -244,7 +247,7 @@ public class DhLightingEngine
|
||||
continue;
|
||||
}
|
||||
|
||||
if (relNeighbourBlockPos.y < neighbourChunk.getMinFilledHeight() || relNeighbourBlockPos.y > neighbourChunk.getMaxBuildHeight())
|
||||
if (relNeighbourBlockPos.y < neighbourChunk.getMinNonEmptyHeight() || relNeighbourBlockPos.y > neighbourChunk.getMaxBuildHeight())
|
||||
{
|
||||
// the light pos is outside the chunk's min/max height,
|
||||
// this can happen if given a chunk that hasn't finished generating
|
||||
|
||||
+25
-19
@@ -220,18 +220,6 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class Mapper
|
||||
{
|
||||
public final WorldGenTask task;
|
||||
public final int dist;
|
||||
public Mapper(WorldGenTask task, int dist)
|
||||
{
|
||||
this.task = task;
|
||||
this.dist = dist;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetPos the position to center the generation around
|
||||
@@ -549,6 +537,19 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
|
||||
|
||||
|
||||
//=======//
|
||||
// debug //
|
||||
//=======//
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer renderer)
|
||||
{
|
||||
this.waitingTasks.keySet().forEach((pos) -> { renderer.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.blue)); });
|
||||
this.inProgressGenTasksByLodPos.forEach((pos, t) -> { renderer.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.red)); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
@@ -586,15 +587,20 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
|
||||
|
||||
|
||||
//=======//
|
||||
// debug //
|
||||
//=======//
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer renderer)
|
||||
private static class Mapper
|
||||
{
|
||||
this.waitingTasks.keySet().forEach((pos) -> { renderer.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.blue)); });
|
||||
this.inProgressGenTasksByLodPos.forEach((pos, t) -> { renderer.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.red)); });
|
||||
public final WorldGenTask task;
|
||||
public final int dist;
|
||||
public Mapper(WorldGenTask task, int dist)
|
||||
{
|
||||
this.task = task;
|
||||
this.dist = dist;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ public class GitlabGetter
|
||||
public static URL getLatestForVersion(String mcVer)
|
||||
{
|
||||
try {
|
||||
return new URL("https://gitlab.com/jeseibel/minecraft-lod-mod/-/jobs/artifacts/main/download?job=build:%20[" + mcVer + "]");
|
||||
return new URL("https://gitlab.com/jeseibel/distant-horizons/-/jobs/artifacts/main/download?job=build:%20[" + mcVer + "]");
|
||||
} catch (Exception e) { e.printStackTrace(); return null; } // This should always be safe (unless you stuff up **badly** somewhere)
|
||||
}
|
||||
}
|
||||
|
||||
+39
-22
@@ -33,7 +33,6 @@ import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
|
||||
import com.seibel.distanthorizons.core.render.glObject.buffer.QuadElementBuffer;
|
||||
import com.seibel.distanthorizons.core.render.glObject.texture.*;
|
||||
import com.seibel.distanthorizons.core.render.renderer.shaders.*;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
@@ -212,12 +211,6 @@ public class LodRenderer
|
||||
}
|
||||
}
|
||||
|
||||
public void resize(int width, int height)
|
||||
{
|
||||
this.colorTexture.resize(width, height);
|
||||
this.depthTexture.resize(width, height, EDhDepthBufferFormat.DEPTH32F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
@@ -297,18 +290,34 @@ public class LodRenderer
|
||||
{
|
||||
this.cachedWidth = MC_RENDER.getTargetFrameBufferViewportWidth();
|
||||
this.cachedHeight = MC_RENDER.getTargetFrameBufferViewportHeight();
|
||||
this.resize(this.cachedWidth, this.cachedHeight);
|
||||
|
||||
// just resizing the textures doesn't work when Optifine is present,
|
||||
// so recreate the textures with the new size instead
|
||||
this.createColorAndDepthTextures();
|
||||
}
|
||||
|
||||
this.setActiveFramebufferId(framebuffer.getId());
|
||||
this.setActiveDepthTextureId(depthTexture.getTextureId());
|
||||
this.setActiveColorTextureId(colorTexture.getTextureId());
|
||||
this.setActiveFramebufferId(this.framebuffer.getId());
|
||||
this.setActiveDepthTextureId(this.depthTexture.getTextureId());
|
||||
this.setActiveColorTextureId(this.colorTexture.getTextureId());
|
||||
// Bind LOD frame buffer
|
||||
this.framebuffer.bind();
|
||||
|
||||
|
||||
if (this.usingMcFrameBuffer)
|
||||
{
|
||||
// recreating the GL State at this point is necessary in order to get the correct depth texture
|
||||
minecraftGlState = new GLState();
|
||||
if (ENABLE_DUMP_GL_STATE)
|
||||
{
|
||||
tickLogger.debug("Re-saving GL state due to Optifine presence: " + minecraftGlState); //
|
||||
}
|
||||
|
||||
|
||||
// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
|
||||
// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
|
||||
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F);
|
||||
|
||||
|
||||
// don't clear the color texture, that removes the sky
|
||||
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
@@ -542,17 +551,8 @@ public class LodRenderer
|
||||
this.usingMcFrameBuffer = false;
|
||||
}
|
||||
|
||||
// color and depth texture
|
||||
this.colorTexture = DhColorTexture.builder().setDimensions(MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight())
|
||||
.setInternalFormat(EDhInternalTextureFormat.RGBA8)
|
||||
.setPixelType(EDhPixelType.UNSIGNED_BYTE)
|
||||
.setPixelFormat(EDhPixelFormat.RGBA)
|
||||
.build();
|
||||
this.depthTexture = new DHDepthTexture(MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight(), EDhDepthBufferFormat.DEPTH32F);
|
||||
|
||||
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F);
|
||||
this.framebuffer.addColorAttachment(0, this.colorTexture.getTextureId());
|
||||
|
||||
// create and bind the necessary textures
|
||||
this.createColorAndDepthTextures();
|
||||
this.cachedWidth = MC_RENDER.getTargetFrameBufferViewportWidth();
|
||||
this.cachedHeight = MC_RENDER.getTargetFrameBufferViewportHeight();
|
||||
|
||||
@@ -570,6 +570,23 @@ public class LodRenderer
|
||||
this.setupLock.unlock();
|
||||
}
|
||||
}
|
||||
/** also binds the new textures to the {@link LodRenderer#framebuffer} */
|
||||
private void createColorAndDepthTextures()
|
||||
{
|
||||
// don't use the cached width/height just in case they haven't been set yet
|
||||
|
||||
this.colorTexture = DhColorTexture.builder().setDimensions(MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight())
|
||||
.setInternalFormat(EDhInternalTextureFormat.RGBA8)
|
||||
.setPixelType(EDhPixelType.UNSIGNED_BYTE)
|
||||
.setPixelFormat(EDhPixelFormat.RGBA)
|
||||
.build();
|
||||
this.depthTexture = new DHDepthTexture(MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight(), EDhDepthBufferFormat.DEPTH32F);
|
||||
|
||||
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F);
|
||||
this.framebuffer.addColorAttachment(0, this.colorTexture.getTextureId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Color getFogColor(float partialTicks)
|
||||
{
|
||||
|
||||
+2
-3
@@ -63,7 +63,6 @@ public class SSAORenderer
|
||||
this.init = true;
|
||||
|
||||
SSAOShader.INSTANCE.init();
|
||||
|
||||
SSAOApplyShader.INSTANCE.init();
|
||||
}
|
||||
|
||||
@@ -113,13 +112,13 @@ public class SSAORenderer
|
||||
this.createFramebuffer(width, height);
|
||||
}
|
||||
|
||||
SSAOShader.INSTANCE.FrameBuffer = this.ssaoFramebuffer;
|
||||
SSAOShader.INSTANCE.frameBuffer = this.ssaoFramebuffer;
|
||||
SSAOShader.INSTANCE.setProjectionMatrix(projectionMatrix);
|
||||
SSAOShader.INSTANCE.render(partialTicks);
|
||||
|
||||
primaryState.restore();
|
||||
|
||||
SSAOApplyShader.INSTANCE.BufferTexture = this.ssaoTexture;
|
||||
SSAOApplyShader.INSTANCE.ssaoTexture = this.ssaoTexture;
|
||||
SSAOApplyShader.INSTANCE.render(partialTicks);
|
||||
|
||||
state.restore();
|
||||
|
||||
+1
-4
@@ -61,10 +61,7 @@ public abstract class AbstractShaderRenderer
|
||||
this.shader.unbind();
|
||||
}
|
||||
|
||||
public void free()
|
||||
{
|
||||
this.shader.free();
|
||||
}
|
||||
public void free() { this.shader.free(); }
|
||||
|
||||
protected void onInit() {}
|
||||
|
||||
|
||||
+1
@@ -162,4 +162,5 @@ public class FogShader extends AbstractShaderRenderer
|
||||
|
||||
state.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-5
@@ -39,7 +39,7 @@ public class SSAOApplyShader extends AbstractShaderRenderer
|
||||
{
|
||||
public static SSAOApplyShader INSTANCE = new SSAOApplyShader();
|
||||
|
||||
public int BufferTexture;
|
||||
public int ssaoTexture;
|
||||
|
||||
// uniforms
|
||||
public int gSSAOMapUniform;
|
||||
@@ -76,11 +76,10 @@ public class SSAOApplyShader extends AbstractShaderRenderer
|
||||
GL32.glUniform1i(this.gDepthMapUniform, 0);
|
||||
|
||||
GL32.glActiveTexture(GL32.GL_TEXTURE1);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.BufferTexture);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
|
||||
GL32.glUniform1i(this.gSSAOMapUniform, 1);
|
||||
|
||||
GL32.glUniform1i(this.gBlurRadiusUniform,
|
||||
Config.Client.Advanced.Graphics.Ssao.blurRadius.get());
|
||||
GL32.glUniform1i(this.gBlurRadiusUniform, Config.Client.Advanced.Graphics.Ssao.blurRadius.get());
|
||||
|
||||
if (this.gViewSizeUniform >= 0)
|
||||
{
|
||||
@@ -115,7 +114,7 @@ public class SSAOApplyShader extends AbstractShaderRenderer
|
||||
GL32.glBlendFuncSeparate(GL32.GL_ZERO, GL32.GL_SRC_ALPHA, GL32.GL_ZERO, GL32.GL_ONE);
|
||||
|
||||
// apply the rendered SSAO to the LODs
|
||||
GL32.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, SSAOShader.INSTANCE.FrameBuffer);
|
||||
GL32.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, SSAOShader.INSTANCE.frameBuffer);
|
||||
GL32.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, LodRenderer.getActiveFramebufferId());
|
||||
|
||||
ScreenQuad.INSTANCE.render();
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ public class SSAOShader extends AbstractShaderRenderer
|
||||
{
|
||||
public static SSAOShader INSTANCE = new SSAOShader();
|
||||
|
||||
public int FrameBuffer;
|
||||
public int frameBuffer;
|
||||
|
||||
private Mat4f projection;
|
||||
private Mat4f invertedProjection;
|
||||
@@ -115,7 +115,7 @@ public class SSAOShader extends AbstractShaderRenderer
|
||||
@Override
|
||||
protected void onRender()
|
||||
{
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.FrameBuffer);
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
|
||||
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||
GL32.glDisable(GL32.GL_DEPTH_TEST);
|
||||
GL32.glDisable(GL32.GL_BLEND);
|
||||
|
||||
@@ -68,17 +68,17 @@ public class ThreadPools
|
||||
public static final DhThreadFactory LIGHT_POPULATOR_THREAD_FACTORY = new DhThreadFactory("LOD Builder - Light Populator", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool lightPopulatorThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getLightPopulatorExecutor() { return lightPopulatorThreadPool.executor; }
|
||||
public static ThreadPoolExecutor getLightPopulatorExecutor() { return (lightPopulatorThreadPool != null) ? lightPopulatorThreadPool.executor : null; }
|
||||
|
||||
public static final DhThreadFactory CHUNK_TO_LOD_BUILDER_THREAD_FACTORY = new DhThreadFactory("LOD Builder - Chunk to Lod Builder", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool chunkToLodBuilderThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getChunkToLodBuilderExecutor() { return chunkToLodBuilderThreadPool.executor; }
|
||||
public static ThreadPoolExecutor getChunkToLodBuilderExecutor() { return (chunkToLodBuilderThreadPool != null) ? chunkToLodBuilderThreadPool.executor : null; }
|
||||
|
||||
public static final DhThreadFactory BUFFER_BUILDER_THREAD_FACTORY = new DhThreadFactory("LOD Builder - Buffer Builder", Thread.MIN_PRIORITY);
|
||||
private static ConfigThreadPool bufferBuilderThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getBufferBuilderExecutor() { return bufferBuilderThreadPool.executor; }
|
||||
public static ThreadPoolExecutor getBufferBuilderExecutor() { return (bufferBuilderThreadPool != null) ? bufferBuilderThreadPool.executor : null; }
|
||||
|
||||
|
||||
/** how many total worker threads can be used */
|
||||
|
||||
@@ -154,8 +154,9 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
|
||||
@Override
|
||||
public CompletableFuture<Void> saveAndFlush() { return CompletableFuture.allOf(this.dhLevels.stream().map(DhClientServerLevel::saveAsync).toArray(CompletableFuture[]::new)); }
|
||||
|
||||
/** synchronized to prevent a rare issue where the server tries closing the same world multiple times in rapid succession. */
|
||||
@Override
|
||||
public void close()
|
||||
public synchronized void close()
|
||||
{
|
||||
// at this point the levels are probably unloaded, so this save call usually generally won't do anything
|
||||
this.saveAndFlush();
|
||||
|
||||
+8
-5
@@ -19,7 +19,6 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.wrapperInterfaces.chunk;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
@@ -29,7 +28,6 @@ import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public interface IChunkWrapper extends IBindable
|
||||
{
|
||||
@@ -40,10 +38,15 @@ public interface IChunkWrapper extends IBindable
|
||||
int getMaxBuildHeight();
|
||||
|
||||
/**
|
||||
* returns the Y level for the first non-empty section in this chunk,
|
||||
* or {@link Integer#MAX_VALUE} if this chunk is completely empty.
|
||||
* returns the Y level for the last non-empty section in this chunk,
|
||||
* or {@link IChunkWrapper#getMinBuildHeight()} if this chunk is completely empty.
|
||||
*/
|
||||
int getMinFilledHeight();
|
||||
int getMinNonEmptyHeight();
|
||||
/**
|
||||
* returns the Y level for the first non-empty section in this chunk,
|
||||
* or {@link IChunkWrapper#getMaxBuildHeight()} if this chunk is completely empty.
|
||||
*/
|
||||
int getMaxNonEmptyHeight();
|
||||
|
||||
/** @return The highest y position of a solid block at the given relative chunk position. */
|
||||
int getSolidHeightMapValue(int xRel, int zRel);
|
||||
|
||||
Reference in New Issue
Block a user