From fdb470b5b388a6f225a0edff1bb0b7968b0aa641 Mon Sep 17 00:00:00 2001 From: coolGi Date: Wed, 19 Jul 2023 22:19:01 +0930 Subject: [PATCH 1/8] Save commit for fog fix --- .../core/render/renderer/LodRenderer.java | 10 +- .../shaders/AbstractShaderRenderer.java | 10 +- .../render/renderer/shaders/DarkShader.java | 11 + .../render/renderer/shaders/FogShader.java | 92 ++++++++ .../render/renderer/shaders/SSAORenderer.java | 196 ++++++++++++++++++ .../render/renderer/shaders/SSAOShader.java | 4 +- core/src/main/resources/shaders/fog/fog.frag | 47 +++-- .../main/resources/shaders/noise/noise.frag | 14 +- .../shaders/{ssao/ao.vert => normal.vert} | 2 + core/src/main/resources/shaders/ssao/ao.frag | 5 + .../resources/shaders/ssao/apply-frag.frag | 2 +- .../src/main/resources/shaders/test/dark.frag | 9 + 12 files changed, 378 insertions(+), 24 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java rename core/src/main/resources/shaders/{ssao/ao.vert => normal.vert} (67%) create mode 100644 core/src/main/resources/shaders/test/dark.frag diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index 92cf2fb42..45262125a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -30,6 +30,9 @@ import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.glObject.GLState; import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer; import com.seibel.distanthorizons.core.render.glObject.buffer.QuadElementBuffer; +import com.seibel.distanthorizons.core.render.renderer.shaders.DarkShader; +import com.seibel.distanthorizons.core.render.renderer.shaders.FogShader; +import com.seibel.distanthorizons.core.render.renderer.shaders.SSAORenderer; import com.seibel.distanthorizons.core.render.renderer.shaders.SSAOShader; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.RenderUtil; @@ -244,7 +247,12 @@ public class LodRenderer bufferHandler.renderOpaque(this); if (Config.Client.Advanced.Graphics.Quality.ssao.get()) { - SSAOShader.INSTANCE.render(partialTicks); +// SSAOShader.INSTANCE.render(partialTicks); + SSAORenderer.INSTANCE.render(partialTicks); + } + { +// FogShader.INSTANCE.render(partialTicks); +// DarkShader.INSTANCE.render(partialTicks); } //======================// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java index 623841f3e..43b6a1704 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/AbstractShaderRenderer.java @@ -6,6 +6,7 @@ import com.seibel.distanthorizons.core.render.glObject.GLState; import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer; import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram; import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL32; @@ -14,6 +15,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; public abstract class AbstractShaderRenderer { + protected static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); protected static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); private static final float[] box_vertices = { @@ -106,7 +108,7 @@ public abstract class AbstractShaderRenderer { this.setApplyShaderUniforms(partialTicks); } GL32.glEnable(GL11.GL_BLEND); - GL32.glBlendFunc(GL32.GL_ZERO, GL32.GL_SRC_ALPHA); + GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA); GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); GL32.glActiveTexture(GL32.GL_TEXTURE0); GL32.glBindTexture(GL32.GL_TEXTURE_2D, shaderTexture); @@ -149,4 +151,10 @@ public abstract class AbstractShaderRenderer { boxBuffer.bind(); boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES); } + + public void free() { + this.shader.free(); + if (this.applyShader != null) + this.applyShader.free(); + } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java new file mode 100644 index 000000000..f9d825b8e --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DarkShader.java @@ -0,0 +1,11 @@ +package com.seibel.distanthorizons.core.render.renderer.shaders; + +import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram; + +public class DarkShader extends AbstractShaderRenderer { + public static DarkShader INSTANCE = new DarkShader(); + + protected DarkShader() { + super(new ShaderProgram("shaders/normal.vert", "shaders/test/dark.frag", "fragColor", new String[] { "vPosition", "color" })); + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java new file mode 100644 index 000000000..4f978a080 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java @@ -0,0 +1,92 @@ +package com.seibel.distanthorizons.core.render.renderer.shaders; + +import com.seibel.distanthorizons.api.enums.rendering.EFogColorMode; +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.render.fog.LodFogConfig; +import com.seibel.distanthorizons.core.render.glObject.shader.Shader; +import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.RenderUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; +import org.lwjgl.opengl.GL32; + +import java.awt.*; + +public class FogShader extends AbstractShaderRenderer { + public static FogShader INSTANCE = new FogShader(LodFogConfig.generateFogConfig()); + private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class); + + // Fog Uniforms + public final int fogColorUniform; + public final int fogScaleUniform; + public final int fogVerticalScaleUniform; + public final int nearFogStartUniform; + public final int nearFogLengthUniform;; + public final int fullFogModeUniform; + + public FogShader(LodFogConfig fogConfig) { + // TODO & Note: This code is a bit jank, so try to update it later (preferably not using something to process the shader) + super(new ShaderProgram( + () -> Shader.loadFile("shaders/normal.vert", false, new StringBuilder()).toString(), + () -> fogConfig.loadAndProcessFragShader("shaders/fog/fog.frag", false).toString(), + "fragColor", new String[] { "vPos", "vPosition", "color" } + )); + + // Fog uniforms + fogColorUniform = this.shader.getUniformLocation("fogColor"); + fullFogModeUniform = this.shader.getUniformLocation("fullFogMode"); + fogScaleUniform = this.shader.tryGetUniformLocation("fogScale"); + fogVerticalScaleUniform = this.shader.tryGetUniformLocation("fogVerticalScale"); + // near + nearFogStartUniform = this.shader.tryGetUniformLocation("nearFogStart"); + nearFogLengthUniform = this.shader.tryGetUniformLocation("nearFogLength"); + } + + + @Override + void setShaderUniforms(float partialTicks) { + int lodDrawDistance = RenderUtil.getFarClipPlaneDistanceInBlocks(); + int vanillaDrawDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH; +// super.bind(); + vanillaDrawDistance += 32; // Give it a 2 chunk boundary for near fog. +// // uniforms +// this.shader.setUniform(combinedMatUniform, combinedMatrix); +// this.shader.setUniform(mircoOffsetUniform, 0.01f); // 0.01 block offset +// +// // setUniform(skyLightUniform, skyLight); +// this.shader.setUniform(lightMapUniform, lightmapBindPoint); +// +// if (worldYOffsetUniform != -1) this.shader.setUniform(worldYOffsetUniform, (float)worldYOffset); + + // Fog + this.shader.setUniform(fullFogModeUniform, MC_RENDER.isFogStateSpecial() ? 1 : 0); + this.shader.setUniform(fogColorUniform, MC_RENDER.isFogStateSpecial() ? getSpecialFogColor(partialTicks) : getFogColor(partialTicks)); + + float nearFogLen = vanillaDrawDistance * 0.2f / lodDrawDistance; + float nearFogStart = vanillaDrawDistance * (VERSION_CONSTANTS.isVanillaRenderedChunkSquare() ? (float)Math.sqrt(2.) : 1.f) / lodDrawDistance; + if (nearFogStartUniform != -1) this.shader.setUniform(nearFogStartUniform, nearFogStart); + if (nearFogLengthUniform != -1) this.shader.setUniform(nearFogLengthUniform, nearFogLen); + if (fogScaleUniform != -1) this.shader.setUniform(fogScaleUniform, 1.f/lodDrawDistance); + if (fogVerticalScaleUniform != -1) this.shader.setUniform(fogVerticalScaleUniform, 1.f/MC.getWrappedClientWorld().getHeight()); + } + + + + private Color getFogColor(float partialTicks) + { + Color fogColor; + + if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EFogColorMode.USE_SKY_COLOR) + fogColor = MC_RENDER.getSkyColor(); + else + fogColor = MC_RENDER.getFogColor(partialTicks); + + return fogColor; + } + private Color getSpecialFogColor(float partialTicks) + { + return MC_RENDER.getSpecialFogColor(partialTicks); + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java new file mode 100644 index 000000000..8625382a9 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java @@ -0,0 +1,196 @@ +package com.seibel.distanthorizons.core.render.renderer.shaders; + +import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.render.glObject.GLState; +import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer; +import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram; +import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.RenderUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.coreapi.util.math.Mat4f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL32; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +// TODO: Move over to SSAOShader +// For some reason this version looks slightly different to that, even tough there isnt much visible change in the code +public class SSAORenderer { + public static SSAORenderer INSTANCE = new SSAORenderer(); + + public SSAORenderer() { + } + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + + private static final float[] box_vertices = { + -1, -1, + 1, -1, + 1, 1, + -1, -1, + 1, 1, + -1, 1, + }; + + ShaderProgram ssaoShader; + ShaderProgram applyShader; + GLVertexBuffer boxBuffer; + VertexAttribute va; + boolean init = false; + + private static final int MAX_KERNEL_SIZE = 32; + private float[] kernel = new float[MAX_KERNEL_SIZE * 3]; + + public void init() { + if (init) return; + + init = true; + va = VertexAttribute.create(); + va.bind(); + // Pos + va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false)); + va.completeAndCheck(Float.BYTES * 2); + ssaoShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag", + "fragColor", new String[]{"vPosition"}); + + applyShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag", + "fragColor", new String[]{"vPosition"}); + + + // Generate kernel + kernel = genKernel(); + // Framebuffer + createBuffer(); + } + + private int width = -1; + private int height = -1; + private int ssaoFramebuffer = -1; + + private int ssaoTexture = -1; + + private void createFramebuffer(int width, int height) { + if (ssaoFramebuffer != -1) { + GL32.glDeleteFramebuffers(ssaoFramebuffer); + ssaoFramebuffer = -1; + } + + if (ssaoTexture != -1) { + GL32.glDeleteTextures(ssaoTexture); + ssaoTexture = -1; + } + + ssaoFramebuffer = GL32.glGenFramebuffers(); + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, ssaoFramebuffer); + + ssaoTexture = GL32.glGenTextures(); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, ssaoTexture); + GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RED, width, height, 0, GL32.GL_RED, GL32.GL_FLOAT, (ByteBuffer) null); + GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_NEAREST); + GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_NEAREST); + GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, ssaoTexture, 0); + } + + private void createBuffer() { + ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES); + buffer.order(ByteOrder.nativeOrder()); + buffer.asFloatBuffer().put(box_vertices); + buffer.rewind(); + boxBuffer = new GLVertexBuffer(false); + boxBuffer.bind(); + boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES); + } + + private static float[] genKernel() { + float[] kernel = new float[MAX_KERNEL_SIZE * 3]; + for (int i = 0; i < MAX_KERNEL_SIZE; i++) { + float sampleX = (float) (Math.random() * 2.0 - 1.0); + float sampleY = (float) (Math.random() * 2.0 - 1.0); + float sampleZ = (float) Math.random(); + + + // Normalize + float magnitude = (float) Math.sqrt(Math.pow(sampleX, 2) + Math.pow(sampleY, 2) + Math.pow(sampleZ, 2)); + sampleX /= magnitude; + sampleY /= magnitude; + sampleZ /= magnitude; + + float scale = i / (float) MAX_KERNEL_SIZE; + float interpolatedScale = (float) (0.1 + (scale * scale) * (0.9)); + + sampleX *= interpolatedScale; + sampleY *= interpolatedScale; + sampleZ *= interpolatedScale; + kernel[i * 3] = sampleX; + kernel[i * 3 + 1] = sampleY; + kernel[i * 3 + 2] = sampleZ; + } + return kernel; + } + + public void render(float partialTicks) { + GLState state = new GLState(); + init(); + //GL32.glDepthMask(false); + int width = MC_RENDER.getTargetFrameBufferViewportWidth(); + int height = MC_RENDER.getTargetFrameBufferViewportHeight(); + + if (this.width != width || this.height != height) { + this.width = width; + this.height = height; + createFramebuffer(width, height); + } + + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, ssaoFramebuffer); + GL32.glViewport(0, 0, width, height); + GL32.glDisable(GL32.GL_DEPTH_TEST); + GL32.glDisable(GL32.GL_BLEND); + GL32.glDisable(GL32.GL_SCISSOR_TEST); + + + Mat4f perspective = Mat4f.perspective( + (float) MC_RENDER.getFov(partialTicks), + MC_RENDER.getTargetFrameBufferViewportWidth() / (float) MC_RENDER.getTargetFrameBufferViewportHeight(), + RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks), + (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2))); + + ssaoShader.bind(); + ssaoShader.setUniform(ssaoShader.getUniformLocation("gProj"), perspective); + ssaoShader.setUniform(ssaoShader.getUniformLocation("gSampleRad"), 3.0f); + ssaoShader.setUniform(ssaoShader.getUniformLocation("gFactor"), 0.8f); + ssaoShader.setUniform(ssaoShader.getUniformLocation("gPower"), 1.0f); + va.bind(); + va.bindBufferToAllBindingPoint(boxBuffer.getId()); + + GL32.glActiveTexture(GL32.GL_TEXTURE0); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId()); + + GL32.glUniform3fv(ssaoShader.getUniformLocation("gKernel"), kernel); + GL32.glUniform1i(ssaoShader.getUniformLocation("gDepthMap"), 0); + GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6); + + applyShader.bind(); + GL32.glEnable(GL11.GL_BLEND); + GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA); + GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); + GL32.glActiveTexture(GL32.GL_TEXTURE0); + GL32.glBindTexture(GL32.GL_TEXTURE_2D, ssaoTexture); + GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6); + + //GL32.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, ssaoFramebuffer); + //GL32.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer()); + //GL32.glBlitFramebuffer( + // 0, 0, width, height, + // 0, 0, width, height, + // GL11.GL_COLOR_BUFFER_BIT, + // GL11.GL_NEAREST + //); + + state.restore(); + } + + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java index 4c3495ee4..db7a18cf6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAOShader.java @@ -15,9 +15,9 @@ public class SSAOShader extends AbstractShaderRenderer { public SSAOShader() { super( - new ShaderProgram("shaders/ssao/ao.vert", "shaders/ssao/ao.frag", + new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag", "fragColor", new String[]{"vPos"}), - new ShaderProgram("shaders/ssao/ao.vert", "shaders/ssao/apply-frag.frag", + new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag", "fragColor", new String[]{"vPos"}) ); diff --git a/core/src/main/resources/shaders/fog/fog.frag b/core/src/main/resources/shaders/fog/fog.frag index 5537efda0..90aaf0352 100644 --- a/core/src/main/resources/shaders/fog/fog.frag +++ b/core/src/main/resources/shaders/fog/fog.frag @@ -1,10 +1,7 @@ -#version 150 core - -in vec4 vertexColor; in vec3 vertexWorldPos; in float vertexYPos; -in vec4 vPos; +in vec2 TexCoord; out vec4 fragColor; @@ -30,6 +27,20 @@ float mixFogThickness(float near, float far, float height); // ========================================================= +// Puts steps in a float +// EG. setting stepSize to 4 then this would be the result of this function +// In: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, ..., 1.1, 1.2, 1.3 +// Out: 0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, ..., 1.0, 1.0, 1.25 +float quantize(float val, int stepSize) { + return floor(val*stepSize)/stepSize; +} + +// The modulus function dosnt exist in GLSL so I made my own +// To speed up the mod function, this only accepts full numbers for y +float mod(float x, int y) { + return x - y * floor(x/y); +} + /** @@ -39,19 +50,31 @@ float mixFogThickness(float near, float far, float height); * version: 2023-6-21 */ void main() { - float horizontalDist = length(vertexWorldPos.xz) * fogScale; - float heightDist = calculateHeightFogDepth( + if (fullFogMode != 0) { + fragColor = vec4(fogColor.r, fogColor.g, fogColor.b, 1.); + } else { + float horizontalDist = length(vertexWorldPos.xz) * fogScale; + float heightDist = calculateHeightFogDepth( vertexWorldPos.y, vertexYPos) * fogVerticalScale; - float farDist = calculateFarFogDepth(horizontalDist, + float farDist = calculateFarFogDepth(horizontalDist, length(vertexWorldPos.xyz) * fogScale, nearFogStart); - float nearFogThickness = getNearFogThickness(horizontalDist); - float farFogThickness = getFarFogThickness(farDist); - float heightFogThickness = getHeightFogThickness(heightDist); - float mixedFogThickness = clamp(mixFogThickness( + float nearFogThickness = getNearFogThickness(horizontalDist); + float farFogThickness = getFarFogThickness(farDist); + float heightFogThickness = getHeightFogThickness(heightDist); + float mixedFogThickness = clamp(mixFogThickness( nearFogThickness, farFogThickness, heightFogThickness), 0.0, 1.0); - fragColor = mix(vertexColor, vec4(fogColor.rgb, 1.0), mixedFogThickness); + fragColor = vec4(fogColor.r, fogColor.g, fogColor.b, mixedFogThickness); + } + if (fragColor.r != 6969.) { + fragColor = vec4( + mod(vertexWorldPos.x, 1), + mod(vertexWorldPos.y, 1), + mod(vertexWorldPos.z, 1), + 1. + ); + } } diff --git a/core/src/main/resources/shaders/noise/noise.frag b/core/src/main/resources/shaders/noise/noise.frag index d64f051dc..4eeff968c 100644 --- a/core/src/main/resources/shaders/noise/noise.frag +++ b/core/src/main/resources/shaders/noise/noise.frag @@ -81,11 +81,11 @@ void main() { ); // For testing - if (vertexColor.r != 69420.) { - fragColor = vec4( - mod(fixedVPos.x, 1), - mod(fixedVPos.y, 1), - mod(fixedVPos.z, 1), - 1f); - } +// if (vertexColor.r != 69420.) { +// fragColor = vec4( +// mod(fixedVPos.x, 1), +// mod(fixedVPos.y, 1), +// mod(fixedVPos.z, 1), +// 1f); +// } } \ No newline at end of file diff --git a/core/src/main/resources/shaders/ssao/ao.vert b/core/src/main/resources/shaders/normal.vert similarity index 67% rename from core/src/main/resources/shaders/ssao/ao.vert rename to core/src/main/resources/shaders/normal.vert index b65ef2cff..656402aa9 100644 --- a/core/src/main/resources/shaders/ssao/ao.vert +++ b/core/src/main/resources/shaders/normal.vert @@ -1,5 +1,6 @@ #version 150 core +in uvec4 vPosition; // Fixme in vec2 vPos; out vec2 TexCoord; @@ -10,6 +11,7 @@ out float vertexYPos; void main() { + vertexWorldPos = vec3(vPosition.x, vPosition.y, vPosition.z); // Fixme gl_Position = vec4(vPos, 1.0, 1.0); TexCoord = vPos.xy * 0.5 + 0.5; } \ No newline at end of file diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index d8d77ccf0..9e3ccf0e8 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -30,6 +30,11 @@ vec3 calcViewPosition(vec2 coords) { vs_pos.xyz = vs_pos.xyz / vs_pos.w; return vs_pos.xyz; } +// The modulus function dosnt exist in GLSL so I made my own +// To speed up the mod function, this only accepts full numbers for y +float mod(float x, int y) { + return x - y * floor(x/y); +} void main() { diff --git a/core/src/main/resources/shaders/ssao/apply-frag.frag b/core/src/main/resources/shaders/ssao/apply-frag.frag index db95aebd8..7cfa9df34 100644 --- a/core/src/main/resources/shaders/ssao/apply-frag.frag +++ b/core/src/main/resources/shaders/ssao/apply-frag.frag @@ -9,5 +9,5 @@ uniform sampler2D gSSAOMap; void main() { - fragColor = vec4(0.0, 0.0, 0.0, texture(gSSAOMap, TexCoord).r); + fragColor = vec4(0.0, 0.0, 0.0, 1-texture(gSSAOMap, TexCoord).r); } \ No newline at end of file diff --git a/core/src/main/resources/shaders/test/dark.frag b/core/src/main/resources/shaders/test/dark.frag new file mode 100644 index 000000000..ab99d05ce --- /dev/null +++ b/core/src/main/resources/shaders/test/dark.frag @@ -0,0 +1,9 @@ +#version 150 core + +out vec4 fragColor; + +// A test shader that makes everything darker +void main() +{ + fragColor = vec4(0., 0., 1., 0.5); +} \ No newline at end of file From 675682d631ff09157119e6b13be8dfb812b5dc0e Mon Sep 17 00:00:00 2001 From: coolGi Date: Thu, 20 Jul 2023 21:06:07 +0930 Subject: [PATCH 2/8] Another save commit for fog fix --- .../core/render/renderer/LodRenderer.java | 10 +++++-- .../render/renderer/shaders/FogShader.java | 30 ++++++++++++------- .../render/renderer/shaders/SSAORenderer.java | 5 +++- core/src/main/resources/shaders/fog/fog.frag | 26 ++++++++++------ core/src/main/resources/shaders/fog/fog.vert | 19 ++++++++++++ core/src/main/resources/shaders/normal.vert | 6 ---- core/src/main/resources/shaders/ssao/ao.frag | 5 ---- 7 files changed, 67 insertions(+), 34 deletions(-) create mode 100644 core/src/main/resources/shaders/fog/fog.vert diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index 45262125a..217318e82 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -79,7 +79,10 @@ public class LodRenderer public void setupOffset(DhBlockPos pos) { Vec3d cam = MC_RENDER.getCameraExactPosition(); - shaderProgram.setModelPos(new Vec3f((float) (pos.x - cam.x), (float) (pos.y - cam.y), (float) (pos.z - cam.z))); + Vec3f modelPos = new Vec3f((float) (pos.x - cam.x), (float) (pos.y - cam.y), (float) (pos.z - cam.z)); + + shaderProgram.setModelPos(modelPos); +// FogShader.INSTANCE.setModelPos(modelPos); } public void drawVbo(GLVertexBuffer vbo) { @@ -206,6 +209,8 @@ public class LodRenderer if (newConfig != null) { shaderProgram.free(); shaderProgram = new LodRenderProgram(newConfig); +// FogShader.INSTANCE.free(); +// FogShader.INSTANCE = new FogShader(newConfig); } shaderProgram.bind(); } @@ -252,7 +257,7 @@ public class LodRenderer } { // FogShader.INSTANCE.render(partialTicks); -// DarkShader.INSTANCE.render(partialTicks); +// DarkShader.INSTANCE.render(partialTicks); // A test shader to make the world darker } //======================// @@ -356,6 +361,7 @@ public class LodRenderer isSetupComplete = false; EVENT_LOGGER.info("Renderer Cleanup Started"); shaderProgram.free(); +// FogShader.INSTANCE.free(); if (quadIBO != null) quadIBO.destroy(false); EVENT_LOGGER.info("Renderer Cleanup Complete"); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java index 4f978a080..87a5805f8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java @@ -10,6 +10,7 @@ import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.RenderUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; import com.seibel.distanthorizons.coreapi.util.math.Mat4f; +import com.seibel.distanthorizons.coreapi.util.math.Vec3f; import org.lwjgl.opengl.GL32; import java.awt.*; @@ -18,6 +19,10 @@ public class FogShader extends AbstractShaderRenderer { public static FogShader INSTANCE = new FogShader(LodFogConfig.generateFogConfig()); private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class); + +// public final int modelOffsetUniform; + public final int worldYOffsetUniform; + // Fog Uniforms public final int fogColorUniform; public final int fogScaleUniform; @@ -27,13 +32,17 @@ public class FogShader extends AbstractShaderRenderer { public final int fullFogModeUniform; public FogShader(LodFogConfig fogConfig) { - // TODO & Note: This code is a bit jank, so try to update it later (preferably not using something to process the shader) + // TODO & Note: This code is a bit jank, so try to make it better later (preferably not using something to process the shader) + // This code is just a temp fix so that it looks fine for the time being + // and even with the jank soloution, i cannot get it to work super(new ShaderProgram( - () -> Shader.loadFile("shaders/normal.vert", false, new StringBuilder()).toString(), + () -> Shader.loadFile("shaders/fog/fog.vert", false, new StringBuilder()).toString(), () -> fogConfig.loadAndProcessFragShader("shaders/fog/fog.frag", false).toString(), - "fragColor", new String[] { "vPos", "vPosition", "color" } + "fragColor", new String[] { "vPosition", "vPos", "color" } )); +// modelOffsetUniform = this.shader.getUniformLocation("modelOffset"); + worldYOffsetUniform = this.shader.getUniformLocation("worldYOffset"); // Fog uniforms fogColorUniform = this.shader.getUniformLocation("fogColor"); fullFogModeUniform = this.shader.getUniformLocation("fullFogMode"); @@ -51,14 +60,9 @@ public class FogShader extends AbstractShaderRenderer { int vanillaDrawDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH; // super.bind(); vanillaDrawDistance += 32; // Give it a 2 chunk boundary for near fog. -// // uniforms -// this.shader.setUniform(combinedMatUniform, combinedMatrix); -// this.shader.setUniform(mircoOffsetUniform, 0.01f); // 0.01 block offset -// -// // setUniform(skyLightUniform, skyLight); -// this.shader.setUniform(lightMapUniform, lightmapBindPoint); -// -// if (worldYOffsetUniform != -1) this.shader.setUniform(worldYOffsetUniform, (float)worldYOffset); + + + this.shader.setUniform(worldYOffsetUniform, (float) MC.getWrappedClientWorld().getMinHeight()); // Fog this.shader.setUniform(fullFogModeUniform, MC_RENDER.isFogStateSpecial() ? 1 : 0); @@ -89,4 +93,8 @@ public class FogShader extends AbstractShaderRenderer { { return MC_RENDER.getSpecialFogColor(partialTicks); } + + public void setModelPos(Vec3f modelPos) { +// this.shader.setUniform(modelOffsetUniform, modelPos); + } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java index 8625382a9..9e7bb8682 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/SSAORenderer.java @@ -192,5 +192,8 @@ public class SSAORenderer { state.restore(); } - + public void free() { + ssaoShader.free(); + applyShader.free(); + } } diff --git a/core/src/main/resources/shaders/fog/fog.frag b/core/src/main/resources/shaders/fog/fog.frag index 90aaf0352..d4a5a4653 100644 --- a/core/src/main/resources/shaders/fog/fog.frag +++ b/core/src/main/resources/shaders/fog/fog.frag @@ -1,7 +1,7 @@ in vec3 vertexWorldPos; in float vertexYPos; -in vec2 TexCoord; +//in vec2 TexCoord; out vec4 fragColor; @@ -67,14 +67,22 @@ void main() { fragColor = vec4(fogColor.r, fogColor.g, fogColor.b, mixedFogThickness); } - if (fragColor.r != 6969.) { - fragColor = vec4( - mod(vertexWorldPos.x, 1), - mod(vertexWorldPos.y, 1), - mod(vertexWorldPos.z, 1), - 1. - ); - } + + // Testing +// if (fragColor.r != 6969.) { // This line is so that the compiler doesnt delete the previos code +//// fragColor = vec4( +//// mod(vertexWorldPos.x, 1), +//// mod(vertexWorldPos.y, 1), +//// mod(vertexWorldPos.z, 1), +//// 1. +//// ); +// fragColor = vec4( +// mod(vertexYPos, 1), +// mod(vertexYPos, 1), +// mod(vertexYPos, 1), +// 1. +// ); +// } } diff --git a/core/src/main/resources/shaders/fog/fog.vert b/core/src/main/resources/shaders/fog/fog.vert new file mode 100644 index 000000000..463249402 --- /dev/null +++ b/core/src/main/resources/shaders/fog/fog.vert @@ -0,0 +1,19 @@ +#version 150 core + + +//uniform vec3 modelOffset; +uniform float worldYOffset; + +in vec2 vPos; +in uvec4 vPosition; +out vec3 vertexWorldPos; +out float vertexYPos; + + +void main() +{ +// vertexWorldPos = vPosition.xyz + modelOffset; + vertexYPos = vPosition.y + worldYOffset; + + gl_Position = vec4(vPos, 1.0, 1.0); +} \ No newline at end of file diff --git a/core/src/main/resources/shaders/normal.vert b/core/src/main/resources/shaders/normal.vert index 656402aa9..1485baf0e 100644 --- a/core/src/main/resources/shaders/normal.vert +++ b/core/src/main/resources/shaders/normal.vert @@ -1,17 +1,11 @@ #version 150 core -in uvec4 vPosition; // Fixme in vec2 vPos; out vec2 TexCoord; -out vec4 vertexColor; -out vec3 vertexWorldPos; -out float vertexYPos; - void main() { - vertexWorldPos = vec3(vPosition.x, vPosition.y, vPosition.z); // Fixme gl_Position = vec4(vPos, 1.0, 1.0); TexCoord = vPos.xy * 0.5 + 0.5; } \ No newline at end of file diff --git a/core/src/main/resources/shaders/ssao/ao.frag b/core/src/main/resources/shaders/ssao/ao.frag index 9e3ccf0e8..d8d77ccf0 100644 --- a/core/src/main/resources/shaders/ssao/ao.frag +++ b/core/src/main/resources/shaders/ssao/ao.frag @@ -30,11 +30,6 @@ vec3 calcViewPosition(vec2 coords) { vs_pos.xyz = vs_pos.xyz / vs_pos.w; return vs_pos.xyz; } -// The modulus function dosnt exist in GLSL so I made my own -// To speed up the mod function, this only accepts full numbers for y -float mod(float x, int y) { - return x - y * floor(x/y); -} void main() { From 57664ff1f10365e6d430b0d4c062a49c95b9d8d5 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Jul 2023 09:34:52 -0500 Subject: [PATCH 3/8] LodDataBuilder reformat --- .../transformers/LodDataBuilder.java | 29 ++++++++++++++----- .../core/level/IDhServerLevel.java | 2 +- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java index db9d2c773..b0e50bc37 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java @@ -10,15 +10,26 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import it.unimi.dsi.fastutil.longs.LongArrayList; -public class LodDataBuilder { +public class LodDataBuilder +{ + private static final IBlockStateWrapper AIR = SingletonInjector.INSTANCE.get(IWrapperFactory.class).getAirBlockStateWrapper(); - public static ChunkSizedFullDataAccessor createChunkData(IChunkWrapper chunkWrapper) { - if (!canGenerateLodFromChunk(chunkWrapper)) return null; - + + + public static ChunkSizedFullDataAccessor createChunkData(IChunkWrapper chunkWrapper) + { + if (!canGenerateLodFromChunk(chunkWrapper)) + { + return null; + } + + ChunkSizedFullDataAccessor chunkData = new ChunkSizedFullDataAccessor(chunkWrapper.getChunkPos()); - for (int x=0; x<16; x++) { - for (int z=0; z<16; z++) { + for (int x=0; x=chunkWrapper.getMinBuildHeight(); y--) { + for (; y>=chunkWrapper.getMinBuildHeight(); y--) + { IBiomeWrapper newBiome = chunkWrapper.getBiome(x, y, z); IBlockStateWrapper newBlockState = chunkWrapper.getBlockState(x, y, z); byte newLight = (byte) ((chunkWrapper.getBlockLight(x,y+1,z) << 4) + chunkWrapper.getSkyLight(x,y+1,z)); - if (!newBiome.equals(biome) || !newBlockState.equals(blockState)) { + if (!newBiome.equals(biome) || !newBlockState.equals(blockState)) + { longs.add(FullDataPointUtil.encode(mappedId, lastY-y, y+1 - chunkWrapper.getMinBuildHeight(), light)); biome = newBiome; blockState = newBlockState; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java index 8ebb43017..500c29eec 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java @@ -4,7 +4,7 @@ import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataFileHa import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; public interface IDhServerLevel extends IDhLevel, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener - { +{ void serverTick(); void doWorldGen(); From f24bc112c36b067789e024b004f62798c940de03 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Jul 2023 11:50:08 -0500 Subject: [PATCH 4/8] Create a new lighting engine --- .../common/DhApiWorldGenerationConfig.java | 2 +- .../distanthorizons/core/config/Config.java | 10 +- .../core/enums/ELodDirection.java | 17 +- .../core/generation/DhLightingEngine.java | 226 ++++++++++++++++++ .../distanthorizons/core/pos/DhBlockPos.java | 24 +- .../block/IBlockStateWrapper.java | 15 +- .../chunk/IChunkWrapper.java | 38 ++- .../assets/distanthorizons/lang/en_us.json | 4 +- 8 files changed, 308 insertions(+), 28 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/common/DhApiWorldGenerationConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/common/DhApiWorldGenerationConfig.java index 45971c836..b69711a46 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/common/DhApiWorldGenerationConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/common/DhApiWorldGenerationConfig.java @@ -52,7 +52,7 @@ public class DhApiWorldGenerationConfig implements IDhApiWorldGenerationConfig @Override public IDhApiConfigValue lightingEngine() - { return new DhApiConfigValue<>(WorldGenerator.lightingEngine); } + { return new DhApiConfigValue<>(WorldGenerator.worldGenLightingEngine); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index 33f325060..c6c788438 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -644,15 +644,15 @@ public class Config */ .build(); - public static ConfigEntry lightingEngine = new ConfigEntry.Builder() - .set(ELightGenerationMode.MINECRAFT) + public static ConfigEntry worldGenLightingEngine = new ConfigEntry.Builder() + .set(ELightGenerationMode.DISTANT_HORIZONS) .comment("" - + " How should distant generation chunk lighting be generated? \n" + + " How should Distant Horizons world generation chunk lighting be handled? \n" + "\n" + ELightGenerationMode.MINECRAFT + ": Use Minecraft's lighting engine to generate chunk lighting. \n" + " Generally higher quality; but may crash MC's lighting engine if there is an issue. \n" - + ELightGenerationMode.DISTANT_HORIZONS + ": Uses Distant Horizons' lighting engine to estimate chunk lighting. \n" - + " Generally lower quality; but more stable for large numbers of world generator threads. \n" + + ELightGenerationMode.DISTANT_HORIZONS + ": Uses Distant Horizons' lighting engine to generate chunk lighting. \n" + + " May not exactly match MC's, but is more stable for large numbers of world generator threads. \n" + "\n" + "This will effect generation speed, but not rendering performance.") .build(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/enums/ELodDirection.java b/core/src/main/java/com/seibel/distanthorizons/core/enums/ELodDirection.java index 4ffd93525..2c62dbd1d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/enums/ELodDirection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/enums/ELodDirection.java @@ -29,7 +29,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Vec3i; /** * An (almost) exact copy of Minecraft's - * Direction enum. + * Direction enum.

* * Up
* Down
@@ -49,7 +49,12 @@ public enum ELodDirection SOUTH(3, 2, 0, "south", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.Z, new Vec3i(0, 0, 1)), WEST(4, 5, 1, "west", ELodDirection.AxisDirection.NEGATIVE, ELodDirection.Axis.X, new Vec3i(-1, 0, 0)), EAST(5, 4, 3, "east", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.X, new Vec3i(1, 0, 0)); - public static final ELodDirection[] DIRECTIONS = new ELodDirection[] { + + /** + * Up, Down, West, East, North, South
+ * Similar to {@link ELodDirection#OPPOSITE_DIRECTIONS}, just with a different order + */ + public static final ELodDirection[] CARDINAL_DIRECTIONS = new ELodDirection[] { ELodDirection.UP, ELodDirection.DOWN, ELodDirection.WEST, @@ -57,6 +62,10 @@ public enum ELodDirection ELodDirection.NORTH, ELodDirection.SOUTH }; + /** + * Up, Down, South, North, East, West
+ * Similar to {@link ELodDirection#CARDINAL_DIRECTIONS}, just with a different order + */ public static final ELodDirection[] OPPOSITE_DIRECTIONS = new ELodDirection[] { ELodDirection.UP, ELodDirection.DOWN, @@ -64,12 +73,14 @@ public enum ELodDirection ELodDirection.NORTH, ELodDirection.EAST, ELodDirection.WEST }; - /** North, South, East, West */ + + /** North, South, East, West */ // TODO rename to state this is just X/Z or flat directions public static final ELodDirection[] ADJ_DIRECTIONS = new ELodDirection[] { ELodDirection.EAST, ELodDirection.WEST, ELodDirection.SOUTH, ELodDirection.NORTH }; + // private final int data3d; // private final int oppositeIndex; // private final int data2d; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java new file mode 100644 index 000000000..6ea2d2380 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java @@ -0,0 +1,226 @@ +package com.seibel.distanthorizons.core.generation; + +import com.seibel.distanthorizons.core.enums.ELodDirection; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhBlockPos; +import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import org.apache.logging.log4j.Logger; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +/** + * This logic was roughly based on + * Starlight's technical documentation + * although there were some changes due to how our lighting engine works in comparison to Minecraft's. + */ +public class DhLightingEngine +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + public static final DhLightingEngine INSTANCE = new DhLightingEngine(); + + + private DhLightingEngine() { } + + + + /** + * Note: depending on the implementation of {@link IChunkWrapper#setDhBlockLight(int, int, int, int)} and {@link IChunkWrapper#setDhSkyLight(int, int, int, int)} + * the light values may be stored in the wrapper itself instead of the wrapped chunk object. + * If that is the case unwrapping the chunk will undo any work this method did. + * + * @param centerChunk the chunk we want to apply lighting to + * @param nearbyChunkList should also contain centerChunk + * @param maxSkyLight should be a value between 0 and 15 + */ + public void lightChunks(IChunkWrapper centerChunk, List nearbyChunkList, int maxSkyLight) + { + DhChunkPos centerChunkPos = centerChunk.getChunkPos(); + + HashMap chunksByChunkPos = new HashMap<>(9); + LinkedList blockLightPosQueue = new LinkedList<>(); + LinkedList skyLightPosQueue = new LinkedList<>(); + + // generate the list of chunk pos we need, + // currently a 3x3 grid + HashSet requestedAdjacentPositions = new HashSet<>(9); + for (int xOffset = -1; xOffset <= 1; xOffset++) + { + for (int zOffset = -1; zOffset <= 1; zOffset++) + { + DhChunkPos adjacentPos = new DhChunkPos(centerChunkPos.x+xOffset, centerChunkPos.z+zOffset); + requestedAdjacentPositions.add(adjacentPos); + } + } + + + // find all adjacent chunks + // and get any necessary info from them + for (IChunkWrapper chunk : nearbyChunkList) + { + if (chunk != null && requestedAdjacentPositions.contains(chunk.getChunkPos())) + { + // remove the newly found position + requestedAdjacentPositions.remove(chunk.getChunkPos()); + + // add the adjacent chunk + chunksByChunkPos.put(chunk.getChunkPos(), chunk); + + + + // get and set the adjacent chunk's initial block lights + List blockLightPosList = chunk.getBlockLightPosList(); + for (DhBlockPos blockLightPos : blockLightPosList) + { + // get the light + DhBlockPos relLightBlockPos = blockLightPos.convertToChunkRelativePos(); + IBlockStateWrapper blockState = chunk.getBlockState(relLightBlockPos); + int lightValue = blockState.getLightEmission(); + blockLightPosQueue.add(new LightPos(blockLightPos, lightValue)); + + // set the light + DhBlockPos relBlockPos = blockLightPos.convertToChunkRelativePos(); + chunk.setDhBlockLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, lightValue); + } + + + // get and set the adjacent chunk's initial skylights, + // if the dimension has skylights + if (maxSkyLight > 0) + { + // 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++) + { + // get the light + int maxY = chunk.getLightBlockingHeightMapValue(relX, relZ); + DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinX() + relX, maxY, chunk.getMinZ() + relZ); + skyLightPosQueue.add(new LightPos(skyLightPos, maxSkyLight)); + + // set the light + DhBlockPos relBlockPos = skyLightPos.convertToChunkRelativePos(); + chunk.setDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, maxSkyLight); + } + } + } + } + + + if (requestedAdjacentPositions.isEmpty()) + { + // we found every chunk we needed, we don't need to keep iterating + break; + } + } + + // validate that at least 1 chunk was found + if (chunksByChunkPos.size() == 0) + { + LOGGER.warn("Attempted to generate lighting for position ["+centerChunkPos+"], but neither that chunk nor any adjacent chunks were found. No chunk lighting was performed."); + return; + } + + + + // block light + this.propagateLightPosList(blockLightPosQueue, chunksByChunkPos, + (neighbourChunk, relBlockPos) -> neighbourChunk.getDhBlockLight(relBlockPos.x, relBlockPos.y, relBlockPos.z), + (neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhBlockLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, newLightValue)); + + // sky light + this.propagateLightPosList(skyLightPosQueue, chunksByChunkPos, + (neighbourChunk, relBlockPos) -> neighbourChunk.getDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z), + (neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, newLightValue)); + + + LOGGER.trace("Finished generating lighting for chunk: ["+centerChunkPos+"]"); + } + + /** Applies each {@link LightPos} from the queue to the given set of {@link IChunkWrapper}'s. */ + private void propagateLightPosList( + LinkedList lightPosQueue, HashMap chunksByChunkPos, + IGetLightFunc getLightFunc, ISetLightFunc setLightFunc) + { + // update each light position + while (!lightPosQueue.isEmpty()) + { + LightPos lightPos = lightPosQueue.poll(); + DhBlockPos pos = lightPos.pos; + int lightValue = lightPos.lightValue; + + // propagate the lighting in each cardinal direction, IE: -x, +x, -y, +y, -z, +z + for (ELodDirection direction : ELodDirection.CARDINAL_DIRECTIONS) + { + DhBlockPos neighbourBlockPos = pos.offset(direction); + DhChunkPos neighbourChunkPos = new DhChunkPos(neighbourBlockPos); + // converting the block pos into a relative position is necessary for accessing the light values in the chunk + DhBlockPos relNeighbourBlockPos = neighbourBlockPos.convertToChunkRelativePos(); + + + // only continue if the light position is inside one of our chunks + IChunkWrapper neighbourChunk = chunksByChunkPos.get(neighbourChunkPos); + if (neighbourChunk == null) + { + // the light pos is outside our generator's range, ignore it + continue; + } + + + int currentBlockLight = getLightFunc.getLight(neighbourChunk, relNeighbourBlockPos); + if (currentBlockLight >= (lightValue - 1)) + { + // short circuit for when the light value at this position + // is already greater-than what we could set it + continue; + } + + + IBlockStateWrapper neighbourBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos); + // Math.max(1, ...) is used so that the propagated light level always drops by at least 1, preventing infinite cycles. + int targetLevel = lightValue - Math.max(1, neighbourBlockState.getOpacity()); + if (targetLevel > currentBlockLight) + { + // this position is darker than the new light value, update/set it + setLightFunc.setLight(neighbourChunk, relNeighbourBlockPos, targetLevel); + + // now that light has been propagated to this blockPos + // we need to queue it up so its neighbours can be propagated as well + lightPosQueue.add(new LightPos(neighbourBlockPos, targetLevel)); + } + } + } + + // propagation complete + } + + + + //================// + // helper classes // + //================// + + @FunctionalInterface + interface IGetLightFunc { int getLight(IChunkWrapper chunk, DhBlockPos pos); } + @FunctionalInterface + interface ISetLightFunc { void setLight(IChunkWrapper chunk, DhBlockPos pos, int lightValue); } + + private static class LightPos + { + public final DhBlockPos pos; + public final int lightValue; + + public LightPos(DhBlockPos pos, int lightValue) + { + this.pos = pos; + this.lightValue = lightValue; + } + } + + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java index 7ee18e412..4e9caee13 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java @@ -19,6 +19,9 @@ package com.seibel.distanthorizons.core.pos; +import com.seibel.distanthorizons.core.enums.ELodDirection; +import com.seibel.distanthorizons.core.util.LodUtil; + import java.util.Objects; public class DhBlockPos { @@ -110,10 +113,23 @@ public class DhBlockPos { return asLong(x, y, z); } - public DhBlockPos offset(int x, int y, int z) - { - return new DhBlockPos(this.x + x, this.y + y, this.z + z); - } + public DhBlockPos offset(ELodDirection direction) { return this.offset(direction.getNormal().x, direction.getNormal().y, direction.getNormal().z); } + public DhBlockPos offset(int x, int y, int z) { return new DhBlockPos(this.x + x, this.y + y, this.z + z); } + + /** Limits the block position to a value between 0 and 15 (inclusive) */ + public DhBlockPos convertToChunkRelativePos() + { + // move the position into the range -15 and +15 + int relX = (this.x % LodUtil.CHUNK_WIDTH); + // if the position is negative move it into the range 0 and 15 + relX = (relX < 0) ? (relX + LodUtil.CHUNK_WIDTH) : relX; + + int relZ = (this.z % LodUtil.CHUNK_WIDTH); + relZ = (relZ < 0) ? (relZ + LodUtil.CHUNK_WIDTH) : relZ; + + // the y value shouldn't need to be changed + return new DhBlockPos(relX, this.y, relZ); + } /** * Can be used to quickly determine the rough distance between two points
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java index c231cf116..5df9357b4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java @@ -2,14 +2,17 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.block; import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; -/** - * A Minecraft version independent way of handling Blocks. - * - * @author James Seibel - * @version 2022-11-12 - */ +/** A Minecraft version independent way of handling Blocks. */ public interface IBlockStateWrapper extends IDhApiBlockStateWrapper { String serialize(); + /** + * Returning a value of 0 means the block is completely transparent. getBlockLightPosList(); + + + default boolean blockPosInsideChunk(DhBlockPos blockPos) { return this.blockPosInsideChunk(blockPos.x, blockPos.y, blockPos.z); } default boolean blockPosInsideChunk(int x, int y, int z) { return (x >= this.getMinX() && x <= this.getMaxX() && y >= this.getMinBuildHeight() && y < this.getMaxBuildHeight() && z >= this.getMinZ() && z <= this.getMaxZ()); } + default boolean blockPosInsideChunk(DhBlockPos2D blockPos) + { + return (blockPos.x >= this.getMinX() && blockPos.x <= this.getMaxX() + && blockPos.z >= this.getMinZ() && blockPos.z <= this.getMaxZ()); + } boolean doesNearbyChunksExist(); String toString(); @@ -78,11 +101,12 @@ public interface IChunkWrapper extends IBindable return hash; } - - IBlockStateWrapper getBlockState(int x, int y, int z); - IBiomeWrapper getBiome(int x, int y, int z); - - DhChunkPos getChunkPos(); + + + default IBlockStateWrapper getBlockState(DhBlockPos pos) { return this.getBlockState(pos.x, pos.y, pos.z); } + IBlockStateWrapper getBlockState(int relX, int relY, int relZ); + + IBiomeWrapper getBiome(int relX, int relY, int relZ); boolean isStillValid(); } diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index f55ca4754..6479a91aa 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -275,9 +275,9 @@ "Distance Generator Mode", "distanthorizons.config.client.advanced.worldGenerator.distantGeneratorMode.@tooltip": "How complicated the generation should be when generating LODs outside the vanilla render distance.\n\n§6§6Fastest:§r Biome only\n§6Best Quality:§r Features (suggested)", - "distanthorizons.config.client.advanced.worldGenerator.lightingEngine": + "distanthorizons.config.client.advanced.worldGenerator.worldGenLightingEngine": "Lighting Engine", - "distanthorizons.config.client.advanced.worldGenerator.lightingEngine.@tooltip": + "distanthorizons.config.client.advanced.worldGenerator.worldGenLightingEngine.@tooltip": "§6Minecraft:§r use Minecraft's lighting engine, gives accurate lighting.\n§6Distant Horizons:§r estimates lighting, shadows won't be as smooth, but is more stable.\n\nIf the LODs appear black, set this to §6Distant Horizons§r.", "distanthorizons.config.client.advanced.worldGenerator.generationPriority": "Generation Priority", From 4df1bd10a9b17902522646a30d8816a08e1518ee Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Jul 2023 12:20:35 -0500 Subject: [PATCH 5/8] Rename DLodDirection -> EDhDirection and rename several methods --- .../render/bufferBuilding/BufferQuad.java | 6 +- .../render/bufferBuilding/ColumnBox.java | 50 ++++----- .../ColumnRenderBufferBuilder.java | 8 +- .../render/bufferBuilding/LodQuadBuilder.java | 22 ++-- .../FullDataToRenderDataTransformer.java | 18 ++-- .../{ELodDirection.java => EDhDirection.java} | 100 +++++++++--------- .../core/generation/DhLightingEngine.java | 6 +- .../distanthorizons/core/pos/DhBlockPos.java | 4 +- .../core/pos/DhSectionPos.java | 4 +- .../core/render/LodRenderSection.java | 11 +- .../core/render/RenderBufferHandler.java | 16 +-- .../chunk/IChunkWrapper.java | 18 ++-- .../minecraft/IMinecraftClientWrapper.java | 4 +- 13 files changed, 133 insertions(+), 134 deletions(-) rename core/src/main/java/com/seibel/distanthorizons/core/enums/{ELodDirection.java => EDhDirection.java} (79%) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java index 23393fb4b..7c96ef1ea 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/BufferQuad.java @@ -20,8 +20,8 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding; import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.util.LodUtil; -import com.seibel.distanthorizons.core.enums.ELodDirection; /** Represents a render-able quad. */ public final class BufferQuad @@ -56,7 +56,7 @@ public final class BufferQuad public final byte skyLight; public final byte blockLight; - public final ELodDirection direction; + public final EDhDirection direction; public boolean hasError = false; @@ -64,7 +64,7 @@ public final class BufferQuad BufferQuad(short x, short y, short z, short widthEastWest, short widthNorthSouthOrUpDown, int color, byte skylight, byte blockLight, - ELodDirection direction) + EDhDirection direction) { if (widthEastWest == 0 || widthNorthSouthOrUpDown == 0) throw new IllegalArgumentException("Size 0 quad!"); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java index 9fb300909..17ce6c588 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java @@ -20,12 +20,12 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.util.RenderDataPointUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; import com.seibel.distanthorizons.core.render.renderer.LodRenderer; -import com.seibel.distanthorizons.core.enums.ELodDirection; import com.seibel.distanthorizons.coreapi.util.MathUtil; public class ColumnBox @@ -100,13 +100,13 @@ public class ColumnBox boolean skipTop = RenderDataPointUtil.doesDataPointExist(topData) && (RenderDataPointUtil.getYMin(topData) == maxY) && !isTopTransparent; if (!skipTop) { - builder.addQuadUp(x, maxY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(ELodDirection.UP)), skyLightTop, blockLight); + builder.addQuadUp(x, maxY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(EDhDirection.UP)), skyLightTop, blockLight); } boolean skipBottom = RenderDataPointUtil.doesDataPointExist(bottomData) && (RenderDataPointUtil.getYMax(bottomData) == minY) && !isBottomTransparent; if (!skipBottom) { - builder.addQuadDown(x, minY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(ELodDirection.DOWN)), skyLightBot, blockLight); + builder.addQuadDown(x, minY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(EDhDirection.DOWN)), skyLightBot, blockLight); } @@ -115,28 +115,28 @@ public class ColumnBox // TODO merge duplicate code //NORTH face vertex creation { - ColumnArrayView[] adjDataNorth = adjData[ELodDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? + ColumnArrayView[] adjDataNorth = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? int adjOverlapNorth = ColorUtil.INVISIBLE; if (adjDataNorth == null) { // add an adjacent face if this is opaque face or transparent over the void if (!isTransparent || overVoid) { - builder.addQuadAdj(ELodDirection.NORTH, x, minY, z, xSize, ySize, color, (byte) 15, blockLight); + builder.addQuadAdj(EDhDirection.NORTH, x, minY, z, xSize, ySize, color, (byte) 15, blockLight); } } else if (adjDataNorth.length == 1) { - makeAdjVerticalQuad(builder, adjDataNorth[0], ELodDirection.NORTH, x, minY, z, xSize, ySize, + makeAdjVerticalQuad(builder, adjDataNorth[0], EDhDirection.NORTH, x, minY, z, xSize, ySize, color, adjOverlapNorth, skyLightTop, blockLight, topData, bottomData); } else { - makeAdjVerticalQuad(builder, adjDataNorth[0], ELodDirection.NORTH, x, minY, z, (short) (xSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataNorth[0], EDhDirection.NORTH, x, minY, z, (short) (xSize / 2), ySize, color, adjOverlapNorth, skyLightTop, blockLight, topData, bottomData); - makeAdjVerticalQuad(builder, adjDataNorth[1], ELodDirection.NORTH, (short) (x + xSize / 2), minY, z, (short) (xSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataNorth[1], EDhDirection.NORTH, (short) (x + xSize / 2), minY, z, (short) (xSize / 2), ySize, color, adjOverlapNorth, skyLightTop, blockLight, topData, bottomData); } @@ -144,26 +144,26 @@ public class ColumnBox //SOUTH face vertex creation { - ColumnArrayView[] adjDataSouth = adjData[ELodDirection.SOUTH.ordinal() - 2]; + ColumnArrayView[] adjDataSouth = adjData[EDhDirection.SOUTH.ordinal() - 2]; int adjOverlapSouth = ColorUtil.INVISIBLE; if (adjDataSouth == null) { if (!isTransparent || overVoid) - builder.addQuadAdj(ELodDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, (byte) 15, blockLight); + builder.addQuadAdj(EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, (byte) 15, blockLight); } else if (adjDataSouth.length == 1) { - makeAdjVerticalQuad(builder, adjDataSouth[0], ELodDirection.SOUTH, x, minY, maxZ, xSize, ySize, + makeAdjVerticalQuad(builder, adjDataSouth[0], EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, adjOverlapSouth, skyLightTop, blockLight, topData, bottomData); } else { - makeAdjVerticalQuad(builder, adjDataSouth[0], ELodDirection.SOUTH, x, minY, maxZ, (short) (xSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataSouth[0], EDhDirection.SOUTH, x, minY, maxZ, (short) (xSize / 2), ySize, color, adjOverlapSouth, skyLightTop, blockLight, topData, bottomData); - makeAdjVerticalQuad(builder, adjDataSouth[1], ELodDirection.SOUTH, (short) (x + xSize / 2), minY, maxZ, (short) (xSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataSouth[1], EDhDirection.SOUTH, (short) (x + xSize / 2), minY, maxZ, (short) (xSize / 2), ySize, color, adjOverlapSouth, skyLightTop, blockLight, topData, bottomData); } @@ -171,25 +171,25 @@ public class ColumnBox //WEST face vertex creation { - ColumnArrayView[] adjDataWest = adjData[ELodDirection.WEST.ordinal() - 2]; + ColumnArrayView[] adjDataWest = adjData[EDhDirection.WEST.ordinal() - 2]; int adjOverlapWest = ColorUtil.INVISIBLE; if (adjDataWest == null) { if (!isTransparent || overVoid) - builder.addQuadAdj(ELodDirection.WEST, x, minY, z, zSize, ySize, color, (byte) 15, blockLight); + builder.addQuadAdj(EDhDirection.WEST, x, minY, z, zSize, ySize, color, (byte) 15, blockLight); } else if (adjDataWest.length == 1) { - makeAdjVerticalQuad(builder, adjDataWest[0], ELodDirection.WEST, x, minY, z, zSize, ySize, + makeAdjVerticalQuad(builder, adjDataWest[0], EDhDirection.WEST, x, minY, z, zSize, ySize, color, adjOverlapWest, skyLightTop, blockLight, topData, bottomData); } else { - makeAdjVerticalQuad(builder, adjDataWest[0], ELodDirection.WEST, x, minY, z, (short) (zSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataWest[0], EDhDirection.WEST, x, minY, z, (short) (zSize / 2), ySize, color, adjOverlapWest, skyLightTop, blockLight, topData, bottomData); - makeAdjVerticalQuad(builder, adjDataWest[1], ELodDirection.WEST, x, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataWest[1], EDhDirection.WEST, x, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize, color, adjOverlapWest, skyLightTop, blockLight, topData, bottomData); } @@ -197,25 +197,25 @@ public class ColumnBox //EAST face vertex creation { - ColumnArrayView[] adjDataEast = adjData[ELodDirection.EAST.ordinal() - 2]; + ColumnArrayView[] adjDataEast = adjData[EDhDirection.EAST.ordinal() - 2]; int adjOverlapEast = ColorUtil.INVISIBLE; - if (adjData[ELodDirection.EAST.ordinal() - 2] == null) + if (adjData[EDhDirection.EAST.ordinal() - 2] == null) { if (!isTransparent || overVoid) - builder.addQuadAdj(ELodDirection.EAST, maxX, minY, z, zSize, ySize, color, (byte) 15, blockLight); + builder.addQuadAdj(EDhDirection.EAST, maxX, minY, z, zSize, ySize, color, (byte) 15, blockLight); } else if (adjDataEast.length == 1) { - makeAdjVerticalQuad(builder, adjDataEast[0], ELodDirection.EAST, maxX, minY, z, zSize, ySize, + makeAdjVerticalQuad(builder, adjDataEast[0], EDhDirection.EAST, maxX, minY, z, zSize, ySize, color, adjOverlapEast, skyLightTop, blockLight, topData, bottomData); } else { - makeAdjVerticalQuad(builder, adjDataEast[0], ELodDirection.EAST, maxX, minY, z, (short) (zSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataEast[0], EDhDirection.EAST, maxX, minY, z, (short) (zSize / 2), ySize, color, adjOverlapEast, skyLightTop, blockLight, topData, bottomData); - makeAdjVerticalQuad(builder, adjDataEast[1], ELodDirection.EAST, maxX, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataEast[1], EDhDirection.EAST, maxX, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize, color, adjOverlapEast, skyLightTop, blockLight, topData, bottomData); } @@ -224,7 +224,7 @@ public class ColumnBox // the overlap color can be used to see faces that shouldn't be rendered private static void makeAdjVerticalQuad( - LodQuadBuilder builder, ColumnArrayView adjColumnView, ELodDirection direction, + LodQuadBuilder builder, ColumnArrayView adjColumnView, EDhDirection direction, short x, short yMin, short z, short horizontalWidth, short ySize, int color, int debugOverlapColor, byte skyLightTop, byte blockLight, long topData, long bottomData) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java index d90cbec5e..bf3652f13 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java @@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding; import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod; import com.seibel.distanthorizons.api.enums.rendering.EDebugRendering; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.enums.EGLProxyContext; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener; @@ -18,7 +19,6 @@ import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.objects.Reference; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; -import com.seibel.distanthorizons.core.enums.ELodDirection; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -215,7 +215,7 @@ public class ColumnRenderBufferBuilder // We avoid cases where the adjPosition is in player chunk while the position is // not // to always have a wall underwater - for (ELodDirection lodDirection : ELodDirection.ADJ_DIRECTIONS) + for (EDhDirection lodDirection : EDhDirection.ADJ_DIRECTIONS) { try { @@ -280,8 +280,8 @@ public class ColumnRenderBufferBuilder adjColumnViews[lodDirection.ordinal() - 2] = new ColumnArrayView[2]; adjColumnViews[lodDirection.ordinal() - 2][0] = adjRenderSource.getVerticalDataPointView(xAdj, zAdj); adjColumnViews[lodDirection.ordinal() - 2][1] = adjRenderSource.getVerticalDataPointView( - xAdj + (lodDirection.getAxis() == ELodDirection.Axis.X ? 0 : 1), - zAdj + (lodDirection.getAxis() == ELodDirection.Axis.Z ? 0 : 1)); + xAdj + (lodDirection.getAxis() == EDhDirection.Axis.X ? 0 : 1), + zAdj + (lodDirection.getAxis() == EDhDirection.Axis.Z ? 0 : 1)); } } catch (RuntimeException e) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java index 90027c8a7..2b23b4a62 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java @@ -23,7 +23,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.*; -import com.seibel.distanthorizons.core.enums.ELodDirection; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.Pos2D; import com.seibel.distanthorizons.core.render.AbstractRenderBuffer; @@ -136,11 +136,11 @@ public class LodQuadBuilder // add quads // //===========// - public void addQuadAdj(ELodDirection dir, short x, short y, short z, + public void addQuadAdj(EDhDirection dir, short x, short y, short z, short widthEastWest, short widthNorthSouthOrUpDown, int color, byte skyLight, byte blockLight) { - if (dir == ELodDirection.DOWN) + if (dir == EDhDirection.DOWN) { throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!"); } @@ -174,9 +174,9 @@ public class LodQuadBuilder return; } - BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, skylight, blocklight, ELodDirection.UP); + BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, skylight, blocklight, EDhDirection.UP); boolean isTransparent = (this.doTransparency && ColorUtil.getAlpha(color) < 255); - ArrayList quadList = isTransparent ? this.transparentQuads[ELodDirection.UP.ordinal()] : this.opaqueQuads[ELodDirection.UP.ordinal()]; + ArrayList quadList = isTransparent ? this.transparentQuads[EDhDirection.UP.ordinal()] : this.opaqueQuads[EDhDirection.UP.ordinal()]; // update the minimum relative height for this quad's positions @@ -214,9 +214,9 @@ public class LodQuadBuilder { if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow) return; - BufferQuad quad = new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, ELodDirection.DOWN); + BufferQuad quad = new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, EDhDirection.DOWN); ArrayList qs = (doTransparency && ColorUtil.getAlpha(color) < 255) - ? transparentQuads[ELodDirection.DOWN.ordinal()] : opaqueQuads[ELodDirection.DOWN.ordinal()]; + ? transparentQuads[EDhDirection.DOWN.ordinal()] : opaqueQuads[EDhDirection.DOWN.ordinal()]; if (!qs.isEmpty() && (qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.EastWest) || qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.NorthSouthOrUpDown)) @@ -238,7 +238,7 @@ public class LodQuadBuilder int[][] quadBase = DIRECTION_VERTEX_IBO_QUAD[quad.direction.ordinal()]; short widthEastWest = quad.widthEastWest; short widthNorthSouth = quad.widthNorthSouthOrUpDown; - ELodDirection.Axis axis = quad.direction.getAxis(); + EDhDirection.Axis axis = quad.direction.getAxis(); for (int i = 0; i < quadBase.length; i++) { short dx, dy, dz; @@ -349,7 +349,7 @@ public class LodQuadBuilder // only run the second merge if the face is the top or bottom - if (directionIndex == ELodDirection.UP.ordinal() || directionIndex == ELodDirection.DOWN.ordinal()) + if (directionIndex == EDhDirection.UP.ordinal() || directionIndex == EDhDirection.DOWN.ordinal()) { mergeCount += mergeQuadsInternal(this.opaqueQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown); if (this.doTransparency) @@ -400,7 +400,7 @@ public class LodQuadBuilder public void fixTransparencyOverVoid() { // make transparent LODs opaque if they are over the void - ListIterator iter = this.transparentQuads[ELodDirection.UP.ordinal()].listIterator(); + ListIterator iter = this.transparentQuads[EDhDirection.UP.ordinal()].listIterator(); if (iter.hasNext()) { BufferQuad currentQuad = iter.next(); @@ -422,7 +422,7 @@ public class LodQuadBuilder // move the now-opaque quad into the opaque list (if not done the quads may render on top of other transparent quads) iter.remove(); - this.opaqueQuads[ELodDirection.UP.ordinal()].add(currentQuad); + this.opaqueQuads[EDhDirection.UP.ordinal()].add(currentQuad); } currentQuad = iter.next(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java index 0334f09ef..a9b0663a5 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java @@ -397,18 +397,18 @@ public class FullDataToRenderDataTransformer // System.arraycopy(result, 0, data, dataOffset, maxVerticalData); // } // -// public static final ELodDirection[] DIRECTIONS = new ELodDirection[] { -// ELodDirection.UP, -// ELodDirection.DOWN, -// ELodDirection.WEST, -// ELodDirection.EAST, -// ELodDirection.NORTH, -// ELodDirection.SOUTH }; +// public static final EDhDirection[] DIRECTIONS = new EDhDirection[] { +// EDhDirection.UP, +// EDhDirection.DOWN, +// EDhDirection.WEST, +// EDhDirection.EAST, +// EDhDirection.NORTH, +// EDhDirection.SOUTH }; // // private boolean hasCliffFace(IChunkWrapper chunk, int x, int y, int z) { -// for (ELodDirection dir : DIRECTIONS) { +// for (EDhDirection dir : DIRECTIONS) { // IBlockDetailWrapper block = chunk.getBlockDetailAtFace(x, y, z, dir); -// if (block == null || !block.hasFaceCullingFor(ELodDirection.OPPOSITE_DIRECTIONS[dir.ordinal()])) +// if (block == null || !block.hasFaceCullingFor(EDhDirection.OPPOSITE_DIRECTIONS[dir.ordinal()])) // return true; // } // return false; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/enums/ELodDirection.java b/core/src/main/java/com/seibel/distanthorizons/core/enums/EDhDirection.java similarity index 79% rename from core/src/main/java/com/seibel/distanthorizons/core/enums/ELodDirection.java rename to core/src/main/java/com/seibel/distanthorizons/core/enums/EDhDirection.java index 2c62dbd1d..6a7f920a0 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/enums/ELodDirection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/enums/EDhDirection.java @@ -41,57 +41,57 @@ import com.seibel.distanthorizons.coreapi.util.math.Vec3i; * @author James Seibel * @version 2021-11-13 */ -public enum ELodDirection +public enum EDhDirection { - DOWN(0, 1, -1, "down", ELodDirection.AxisDirection.NEGATIVE, ELodDirection.Axis.Y, new Vec3i(0, -1, 0)), - UP(1, 0, -1, "up", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.Y, new Vec3i(0, 1, 0)), - NORTH(2, 3, 2, "north", ELodDirection.AxisDirection.NEGATIVE, ELodDirection.Axis.Z, new Vec3i(0, 0, -1)), - SOUTH(3, 2, 0, "south", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.Z, new Vec3i(0, 0, 1)), - WEST(4, 5, 1, "west", ELodDirection.AxisDirection.NEGATIVE, ELodDirection.Axis.X, new Vec3i(-1, 0, 0)), - EAST(5, 4, 3, "east", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.X, new Vec3i(1, 0, 0)); + DOWN(0, 1, -1, "down", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Y, new Vec3i(0, -1, 0)), + UP(1, 0, -1, "up", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Y, new Vec3i(0, 1, 0)), + NORTH(2, 3, 2, "north", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Z, new Vec3i(0, 0, -1)), + SOUTH(3, 2, 0, "south", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Z, new Vec3i(0, 0, 1)), + WEST(4, 5, 1, "west", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.X, new Vec3i(-1, 0, 0)), + EAST(5, 4, 3, "east", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.X, new Vec3i(1, 0, 0)); /** * Up, Down, West, East, North, South
- * Similar to {@link ELodDirection#OPPOSITE_DIRECTIONS}, just with a different order + * Similar to {@link EDhDirection#OPPOSITE_DIRECTIONS}, just with a different order */ - public static final ELodDirection[] CARDINAL_DIRECTIONS = new ELodDirection[] { - ELodDirection.UP, - ELodDirection.DOWN, - ELodDirection.WEST, - ELodDirection.EAST, - ELodDirection.NORTH, - ELodDirection.SOUTH }; + public static final EDhDirection[] CARDINAL_DIRECTIONS = new EDhDirection[] { + EDhDirection.UP, + EDhDirection.DOWN, + EDhDirection.WEST, + EDhDirection.EAST, + EDhDirection.NORTH, + EDhDirection.SOUTH }; /** * Up, Down, South, North, East, West
- * Similar to {@link ELodDirection#CARDINAL_DIRECTIONS}, just with a different order + * Similar to {@link EDhDirection#CARDINAL_DIRECTIONS}, just with a different order */ - public static final ELodDirection[] OPPOSITE_DIRECTIONS = new ELodDirection[] { - ELodDirection.UP, - ELodDirection.DOWN, - ELodDirection.SOUTH, - ELodDirection.NORTH, - ELodDirection.EAST, - ELodDirection.WEST }; + public static final EDhDirection[] OPPOSITE_DIRECTIONS = new EDhDirection[] { + EDhDirection.UP, + EDhDirection.DOWN, + EDhDirection.SOUTH, + EDhDirection.NORTH, + EDhDirection.EAST, + EDhDirection.WEST }; /** North, South, East, West */ // TODO rename to state this is just X/Z or flat directions - public static final ELodDirection[] ADJ_DIRECTIONS = new ELodDirection[] { - ELodDirection.EAST, - ELodDirection.WEST, - ELodDirection.SOUTH, - ELodDirection.NORTH }; + public static final EDhDirection[] ADJ_DIRECTIONS = new EDhDirection[] { + EDhDirection.EAST, + EDhDirection.WEST, + EDhDirection.SOUTH, + EDhDirection.NORTH }; // private final int data3d; // private final int oppositeIndex; // private final int data2d; private final String name; - private final ELodDirection.Axis axis; - private final ELodDirection.AxisDirection axisDirection; + private final EDhDirection.Axis axis; + private final EDhDirection.AxisDirection axisDirection; private final Vec3i normal; - private static final ELodDirection[] VALUES = values(); + private static final EDhDirection[] VALUES = values(); - private static final Map BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(ELodDirection::getName, (p_199787_0_) -> + private static final Map BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(EDhDirection::getName, (p_199787_0_) -> { return p_199787_0_; })); @@ -128,7 +128,7 @@ public enum ELodDirection - ELodDirection(int p_i46016_3_, int p_i46016_4_, int p_i46016_5_, String p_i46016_6_, ELodDirection.AxisDirection p_i46016_7_, ELodDirection.Axis p_i46016_8_, Vec3i p_i46016_9_) + EDhDirection(int p_i46016_3_, int p_i46016_4_, int p_i46016_5_, String p_i46016_6_, EDhDirection.AxisDirection p_i46016_7_, EDhDirection.Axis p_i46016_8_, Vec3i p_i46016_9_) { // this.data3d = p_i46016_3_; // this.data2d = p_i46016_5_; @@ -229,7 +229,7 @@ public enum ELodDirection // return this.data2d; // } - public ELodDirection.AxisDirection getAxisDirection() + public EDhDirection.AxisDirection getAxisDirection() { return this.axisDirection; } @@ -239,7 +239,7 @@ public enum ELodDirection // return from3DDataValue(this.oppositeIndex); // } - public ELodDirection getClockWise() + public EDhDirection getClockWise() { switch (this) { @@ -256,7 +256,7 @@ public enum ELodDirection } } - public ELodDirection getCounterClockWise() + public EDhDirection getCounterClockWise() { switch (this) { @@ -278,12 +278,12 @@ public enum ELodDirection return this.name; } - public ELodDirection.Axis getAxis() + public EDhDirection.Axis getAxis() { return this.axis; } - public static ELodDirection byName(String name) + public static EDhDirection byName(String name) { return name == null ? null : BY_NAME.get(name.toLowerCase(Locale.ROOT)); } @@ -309,17 +309,17 @@ public enum ELodDirection // return from2DDataValue(MathHelper.floor(p_176733_0_ / 90.0D + 0.5D) & 3); // } - public static ELodDirection fromAxisAndDirection(ELodDirection.Axis p_211699_0_, ELodDirection.AxisDirection p_211699_1_) + public static EDhDirection fromAxisAndDirection(EDhDirection.Axis p_211699_0_, EDhDirection.AxisDirection p_211699_1_) { switch (p_211699_0_) { case X: - return p_211699_1_ == ELodDirection.AxisDirection.POSITIVE ? EAST : WEST; + return p_211699_1_ == EDhDirection.AxisDirection.POSITIVE ? EAST : WEST; case Y: - return p_211699_1_ == ELodDirection.AxisDirection.POSITIVE ? UP : DOWN; + return p_211699_1_ == EDhDirection.AxisDirection.POSITIVE ? UP : DOWN; case Z: default: - return p_211699_1_ == ELodDirection.AxisDirection.POSITIVE ? SOUTH : NORTH; + return p_211699_1_ == EDhDirection.AxisDirection.POSITIVE ? SOUTH : NORTH; } } @@ -356,9 +356,9 @@ public enum ELodDirection // return lodDirection; // } - public static ELodDirection get(ELodDirection.AxisDirection p_181076_0_, ELodDirection.Axis p_181076_1_) + public static EDhDirection get(EDhDirection.AxisDirection p_181076_0_, EDhDirection.Axis p_181076_1_) { - for (ELodDirection lodDirection : VALUES) + for (EDhDirection lodDirection : VALUES) { if (lodDirection.getAxisDirection() == p_181076_0_ && lodDirection.getAxis() == p_181076_1_) { @@ -382,7 +382,7 @@ public enum ELodDirection // return this.normal.getX() * f1 + this.normal.getZ() * f2 > 0.0F; // } - public enum Axis implements Predicate + public enum Axis implements Predicate { X("x") { @@ -427,9 +427,9 @@ public enum ELodDirection } }; - private static final ELodDirection.Axis[] VALUES = values(); + private static final EDhDirection.Axis[] VALUES = values(); - private static final Map BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(ELodDirection.Axis::getName, (p_199785_0_) -> + private static final Map BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(EDhDirection.Axis::getName, (p_199785_0_) -> { return p_199785_0_; })); @@ -440,7 +440,7 @@ public enum ELodDirection this.name = name; } - public static ELodDirection.Axis byName(String name) + public static EDhDirection.Axis byName(String name) { return BY_NAME.get(name.toLowerCase(Locale.ROOT)); } @@ -472,7 +472,7 @@ public enum ELodDirection // } @Override - public boolean test(ELodDirection p_test_1_) + public boolean test(EDhDirection p_test_1_) { return p_test_1_ != null && p_test_1_.getAxis() == this; } @@ -521,7 +521,7 @@ public enum ELodDirection return this.name; } - public ELodDirection.AxisDirection opposite() + public EDhDirection.AxisDirection opposite() { return this == POSITIVE ? NEGATIVE : POSITIVE; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java index 6ea2d2380..8fccf1cd7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java @@ -1,6 +1,6 @@ package com.seibel.distanthorizons.core.generation; -import com.seibel.distanthorizons.core.enums.ELodDirection; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; @@ -100,7 +100,7 @@ public class DhLightingEngine { // get the light int maxY = chunk.getLightBlockingHeightMapValue(relX, relZ); - DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinX() + relX, maxY, chunk.getMinZ() + relZ); + DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinBlockX() + relX, maxY, chunk.getMinBlockZ() + relZ); skyLightPosQueue.add(new LightPos(skyLightPos, maxSkyLight)); // set the light @@ -155,7 +155,7 @@ public class DhLightingEngine int lightValue = lightPos.lightValue; // propagate the lighting in each cardinal direction, IE: -x, +x, -y, +y, -z, +z - for (ELodDirection direction : ELodDirection.CARDINAL_DIRECTIONS) + for (EDhDirection direction : EDhDirection.CARDINAL_DIRECTIONS) { DhBlockPos neighbourBlockPos = pos.offset(direction); DhChunkPos neighbourChunkPos = new DhChunkPos(neighbourBlockPos); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java index 4e9caee13..a60618e12 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhBlockPos.java @@ -19,7 +19,7 @@ package com.seibel.distanthorizons.core.pos; -import com.seibel.distanthorizons.core.enums.ELodDirection; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.util.LodUtil; import java.util.Objects; @@ -113,7 +113,7 @@ public class DhBlockPos { return asLong(x, y, z); } - public DhBlockPos offset(ELodDirection direction) { return this.offset(direction.getNormal().x, direction.getNormal().y, direction.getNormal().z); } + public DhBlockPos offset(EDhDirection direction) { return this.offset(direction.getNormal().x, direction.getNormal().y, direction.getNormal().z); } public DhBlockPos offset(int x, int y, int z) { return new DhBlockPos(this.x + x, this.y + y, this.z + z); } /** Limits the block position to a value between 0 and 15 (inclusive) */ diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index ae9edde62..b0d7bfdf2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -1,6 +1,6 @@ package com.seibel.distanthorizons.core.pos; -import com.seibel.distanthorizons.core.enums.ELodDirection; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; import com.seibel.distanthorizons.core.util.LodUtil; import org.jetbrains.annotations.Nullable; @@ -184,7 +184,7 @@ public class DhSectionPos public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.sectionDetailLevel + 1), BitShiftUtil.half(this.sectionX), BitShiftUtil.half(this.sectionZ)); } - public DhSectionPos getAdjacentPos(ELodDirection dir) + public DhSectionPos getAdjacentPos(EDhDirection dir) { return new DhSectionPos(this.sectionDetailLevel, this.sectionX + dir.getNormal().x, diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index 7675cbf2e..3a85d2dec 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.render; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.file.renderfile.ILodRenderSourceProvider; import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; @@ -11,7 +12,6 @@ import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.objects.Reference; import com.seibel.distanthorizons.core.util.objects.quadTree.QuadTree; import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBuffer; -import com.seibel.distanthorizons.core.enums.ELodDirection; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import org.apache.logging.log4j.Logger; @@ -20,7 +20,6 @@ import java.util.Objects; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** @@ -224,8 +223,8 @@ public class LodRenderSection implements IDebugRenderable private LodRenderSection[] getNeighbors() { - LodRenderSection[] adjacents = new LodRenderSection[ELodDirection.ADJ_DIRECTIONS.length]; - for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) { + LodRenderSection[] adjacents = new LodRenderSection[EDhDirection.ADJ_DIRECTIONS.length]; + for (EDhDirection direction : EDhDirection.ADJ_DIRECTIONS) { try { DhSectionPos adjPos = pos.getAdjacentPos(direction); LodRenderSection adjRenderSection = parentQuadTree.getValue(adjPos); @@ -285,8 +284,8 @@ public class LodRenderSection implements IDebugRenderable tellNeighborsUpdated(); } LodRenderSection[] adjacents = getNeighbors(); - ColumnRenderSource[] adjacentSources = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length]; - for (int i = 0; i < ELodDirection.ADJ_DIRECTIONS.length; i++) { + ColumnRenderSource[] adjacentSources = new ColumnRenderSource[EDhDirection.ADJ_DIRECTIONS.length]; + for (int i = 0; i < EDhDirection.ADJ_DIRECTIONS.length; i++) { LodRenderSection adj = adjacents[i]; if (adj != null) { adjacentSources[i] = adj.getRenderSource(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java index d21feac49..eed83d04f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java @@ -1,11 +1,11 @@ package com.seibel.distanthorizons.core.render; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.pos.Pos2D; import com.seibel.distanthorizons.core.util.objects.SortedArraySet; import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode; -import com.seibel.distanthorizons.core.enums.ELodDirection; import com.seibel.distanthorizons.core.render.renderer.LodRenderer; import com.seibel.distanthorizons.coreapi.util.math.Vec3f; import org.apache.logging.log4j.Logger; @@ -45,16 +45,16 @@ public class RenderBufferHandler */ public void buildRenderListAndUpdateSections(Vec3f lookForwardVector) { - ELodDirection[] axisDirections = new ELodDirection[3]; + EDhDirection[] axisDirections = new EDhDirection[3]; // Do the axis that are the longest first (i.e. the largest absolute value of the lookForwardVector), // with the sign being the opposite of the respective lookForwardVector component's sign float absX = Math.abs(lookForwardVector.x); float absY = Math.abs(lookForwardVector.y); float absZ = Math.abs(lookForwardVector.z); - ELodDirection xDir = lookForwardVector.x < 0 ? ELodDirection.EAST : ELodDirection.WEST; - ELodDirection yDir = lookForwardVector.y < 0 ? ELodDirection.UP : ELodDirection.DOWN; - ELodDirection zDir = lookForwardVector.z < 0 ? ELodDirection.SOUTH : ELodDirection.NORTH; + EDhDirection xDir = lookForwardVector.x < 0 ? EDhDirection.EAST : EDhDirection.WEST; + EDhDirection yDir = lookForwardVector.y < 0 ? EDhDirection.UP : EDhDirection.DOWN; + EDhDirection zDir = lookForwardVector.z < 0 ? EDhDirection.SOUTH : EDhDirection.NORTH; if (absX >= absY && absX >= absZ) { @@ -112,7 +112,7 @@ public class RenderBufferHandler return bManhattanDistance - aManhattanDistance; } - for (ELodDirection axisDirection : axisDirections) + for (EDhDirection axisDirection : axisDirections) { if (axisDirection.getAxis().isVertical()) { @@ -120,7 +120,7 @@ public class RenderBufferHandler } int abPosDifference; - if (axisDirection.getAxis().equals(ELodDirection.Axis.X)) + if (axisDirection.getAxis().equals(EDhDirection.Axis.X)) { abPosDifference = aPos.x - bPos.x; } @@ -134,7 +134,7 @@ public class RenderBufferHandler continue; } - if (axisDirection.getAxisDirection().equals(ELodDirection.AxisDirection.NEGATIVE)) + if (axisDirection.getAxisDirection().equals(EDhDirection.AxisDirection.NEGATIVE)) { abPosDifference = -abPosDifference; // Reverse the sign } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java index d2b68252f..f699a174f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java @@ -45,10 +45,10 @@ public interface IChunkWrapper extends IBindable */ int getLightBlockingHeightMapValue(int xRel, int zRel); - int getMaxX(); - int getMaxZ(); - int getMinX(); - int getMinZ(); + int getMaxBlockX(); + int getMaxBlockZ(); + int getMinBlockX(); + int getMinBlockZ(); long getLongChunkPos(); @@ -72,17 +72,17 @@ public interface IChunkWrapper extends IBindable default boolean blockPosInsideChunk(DhBlockPos blockPos) { return this.blockPosInsideChunk(blockPos.x, blockPos.y, blockPos.z); } default boolean blockPosInsideChunk(int x, int y, int z) { - return (x >= this.getMinX() && x <= this.getMaxX() + return (x >= this.getMinBlockX() && x <= this.getMaxBlockX() && y >= this.getMinBuildHeight() && y < this.getMaxBuildHeight() - && z >= this.getMinZ() && z <= this.getMaxZ()); + && z >= this.getMinBlockZ() && z <= this.getMaxBlockZ()); } default boolean blockPosInsideChunk(DhBlockPos2D blockPos) { - return (blockPos.x >= this.getMinX() && blockPos.x <= this.getMaxX() - && blockPos.z >= this.getMinZ() && blockPos.z <= this.getMaxZ()); + return (blockPos.x >= this.getMinBlockX() && blockPos.x <= this.getMaxBlockX() + && blockPos.z >= this.getMinBlockZ() && blockPos.z <= this.getMaxBlockZ()); } - boolean doesNearbyChunksExist(); + boolean doNearbyChunksExist(); String toString(); /** This is a bad hash algorithm, but can be used for rough debugging. */ diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java index d96e144cc..b9aec9bd1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java @@ -23,10 +23,10 @@ import java.io.File; import java.util.ArrayList; import java.util.UUID; +import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.coreapi.ModInfo; -import com.seibel.distanthorizons.core.enums.ELodDirection; import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import org.apache.logging.log4j.Level; @@ -57,7 +57,7 @@ public interface IMinecraftClientWrapper extends IBindable // method wrappers // //=================// - float getShade(ELodDirection lodDirection); + float getShade(EDhDirection lodDirection); boolean hasSinglePlayerServer(); boolean clientConnectedToDedicatedServer(); From 860374fd1bb35eb3f8770d6f7d0d30ad80f2c01a Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Jul 2023 12:34:15 -0500 Subject: [PATCH 6/8] Add a config for world gen timeout --- .../com/seibel/distanthorizons/core/config/Config.java | 9 +++++++++ .../resources/assets/distanthorizons/lang/en_us.json | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index c6c788438..5f247c80c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -657,6 +657,15 @@ public class Config + "This will effect generation speed, but not rendering performance.") .build(); + public static ConfigEntry worldGenerationTimeoutLengthInSeconds = new ConfigEntry.Builder() + .setMinDefaultMax(5, 60, 60*10/*10 minutes*/) + .comment("" + + "How long should a world generator thread run for before timing out? \n" + + "Note: If you are experiencing timeout errors it is better to lower your CPU usage first \n" + + "via the thread config before changing this value. \n" + + "") + .build(); + // deprecated and not implemented, can be made public if we ever re-implement it @Deprecated private static ConfigEntry generationPriority = new ConfigEntry.Builder() diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index 6479a91aa..1f814acfc 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -279,6 +279,10 @@ "Lighting Engine", "distanthorizons.config.client.advanced.worldGenerator.worldGenLightingEngine.@tooltip": "§6Minecraft:§r use Minecraft's lighting engine, gives accurate lighting.\n§6Distant Horizons:§r estimates lighting, shadows won't be as smooth, but is more stable.\n\nIf the LODs appear black, set this to §6Distant Horizons§r.", + "distanthorizons.config.client.advanced.worldGenerator.worldGenerationTimeoutLengthInSeconds": + "Timeout Length In Seconds", + "distanthorizons.config.client.advanced.worldGenerator.worldGenerationTimeoutLengthInSeconds.@tooltip": + "How long should a world generator thread run for before timing out? \nNote: If you are experiencing timeout errors it is better to lower your CPU usage first \nvia the thread config before changing this value.", "distanthorizons.config.client.advanced.worldGenerator.generationPriority": "Generation Priority", "distanthorizons.config.client.advanced.worldGenerator.generationPriority.@tooltip": From 86683d85c8610279b1310f2aa6c0195b6dffe552 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Jul 2023 18:18:38 -0500 Subject: [PATCH 7/8] Increase FullDataSource version numbers from 0 -> 1 This was done to prevent errors with the BlockStateWrapper (de)serialization change --- .../core/dataObjects/fullData/FullDataPointIdMap.java | 7 +++++-- .../fullData/sources/CompleteFullDataSource.java | 2 +- .../sources/HighDetailIncompleteFullDataSource.java | 2 +- .../sources/LowDetailIncompleteFullDataSource.java | 2 +- .../core/file/fullDatafile/FullDataMetaFile.java | 5 +++-- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java index f1fb5a740..74d1e1645 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java @@ -25,6 +25,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; */ public class FullDataPointIdMap { + public static final String SEPARATOR_STRING = "_DH-BSW_"; + + // FIXME: Improve performance maybe? private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); @@ -157,11 +160,11 @@ public class FullDataPointIdMap } - public String serialize() { return this.biome.serialize() + " " + this.blockState.serialize(); } + public String serialize() { return this.biome.serialize() + SEPARATOR_STRING + this.blockState.serialize(); } public static Entry deserialize(String str) throws IOException, InterruptedException { - String[] stringArray = str.split(" "); + String[] stringArray = str.split(SEPARATOR_STRING); if (stringArray.length != 2) { throw new IOException("Failed to deserialize BiomeBlockStateEntry"); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java index ea1d91959..98b7bf8bf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java @@ -37,7 +37,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu /** measured in dataPoints */ public static final int WIDTH = BitShiftUtil.powerOfTwo(SECTION_SIZE_OFFSET); - public static final byte DATA_FORMAT_VERSION = 0; + public static final byte DATA_FORMAT_VERSION = 1; /** written to the binary file to mark what {@link IFullDataSource} the binary file corresponds to */ public static final long TYPE_ID = "CompleteFullDataSource".hashCode(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java index a50ede306..6b67c65ad 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java @@ -51,7 +51,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo /** aka max detail level */ public static final byte MAX_SECTION_DETAIL = SECTION_SIZE_OFFSET + SPARSE_UNIT_DETAIL; - public static final byte DATA_FORMAT_VERSION = 0; + public static final byte DATA_FORMAT_VERSION = 1; /** written to the binary file to mark what {@link IFullDataSource} the binary file corresponds to */ public static final long TYPE_ID = "HighDetailIncompleteFullDataSource".hashCode(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java index 80efef90f..25de2c369 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java @@ -42,7 +42,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp /** measured in dataPoints */ public static final int WIDTH = BitShiftUtil.powerOfTwo(SECTION_SIZE_OFFSET); - public static final byte DATA_FORMAT_VERSION = 0; // TODO rename to data format version + public static final byte DATA_FORMAT_VERSION = 1; /** written to the binary file to mark what {@link IFullDataSource} the binary file corresponds to */ public static final long TYPE_ID = "LowDetailIncompleteFullDataSource".hashCode(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java index 9ec036858..168d04a28 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java @@ -205,8 +205,9 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I }) .whenComplete((fullDataSource, ex) -> { - if (ex != null && !LodUtil.isInterruptOrReject(ex)) { - LOGGER.error("Error updating file "+this.file+": ", ex); + if (ex != null && !LodUtil.isInterruptOrReject(ex)) + { + LOGGER.error("Error updating file ["+this.file+"]: ", ex); } if (fullDataSource != null) { From a00cfbb7dea9b8c6dc08c831498eb8a739f37b04 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Jul 2023 21:02:50 -0500 Subject: [PATCH 8/8] Fix lighting propagation when connected to a server --- .../core/api/internal/ClientApi.java | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java index 69ca993ca..644d47172 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java @@ -23,6 +23,7 @@ import com.seibel.distanthorizons.api.methods.events.abstractEvents.*; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; +import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.world.*; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.core.level.IDhClientLevel; @@ -133,29 +134,41 @@ public class ClientApi } } - public void clientChunkLoadEvent(IChunkWrapper chunk, IClientLevelWrapper level) + public void clientChunkLoadEvent(IChunkWrapper chunk, IClientLevelWrapper level) { this.applyChunkUpdate(chunk, level); } + public void clientChunkSaveEvent(IChunkWrapper chunk, IClientLevelWrapper level) { this.applyChunkUpdate(chunk, level); } + private void applyChunkUpdate(IChunkWrapper chunk, IClientLevelWrapper level) { - if (SharedApi.getEnvironment() == EWorldEnvironment.Client_Only) + // if the user is in a single player world the chunk updates are handled on the server side + if (SharedApi.getEnvironment() != EWorldEnvironment.Client_Only) { - IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level); - if (dhLevel != null) + return; + } + + // only continue if the level is still loaded + IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level); + if (dhLevel == null) + { + return; + } + + + dhLevel.updateChunkAsync(chunk); + + // also update any existing neighbour chunks so lighting changes are propagated correctly + for (int xOffset = -1; xOffset <= 1; xOffset++) + { + for (int zOffset = -1; zOffset <= 1; zOffset++) { - dhLevel.updateChunkAsync(chunk); - } - } - } - - public void clientChunkSaveEvent(IChunkWrapper chunk, IClientLevelWrapper level) - { - if (SharedApi.getEnvironment() == EWorldEnvironment.Client_Only) - { - IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level); - if (dhLevel != null) - { - dhLevel.updateChunkAsync(chunk); + DhChunkPos neighbourPos = new DhChunkPos(chunk.getChunkPos().x+xOffset, chunk.getChunkPos().z+zOffset); + IChunkWrapper neighbourChunk = dhLevel.getLevelWrapper().tryGetChunk(neighbourPos); + if (neighbourChunk != null) + { + dhLevel.updateChunkAsync(neighbourChunk); + } } } } + public void clientLevelUnloadEvent(IClientLevelWrapper level) {