diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderLoader.java b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderLoader.java index 621513a8e..115c736c8 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderLoader.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderLoader.java @@ -1,6 +1,8 @@ package com.seibel.lod.core.a7.datatype.column; import com.seibel.lod.core.a7.datatype.LodDataSource; +import com.seibel.lod.core.a7.datatype.full.FullDataSource; +import com.seibel.lod.core.a7.datatype.transform.FullToColumnTransformer; import com.seibel.lod.core.a7.level.IClientLevel; import com.seibel.lod.core.a7.datatype.LodRenderSource; import com.seibel.lod.core.a7.datatype.RenderSourceLoader; @@ -27,7 +29,9 @@ public class ColumnRenderLoader extends RenderSourceLoader { @Override public LodRenderSource createRender(LodDataSource dataSource, IClientLevel level) { - //TODO + if (dataSource instanceof FullDataSource) { + return FullToColumnTransformer.transformFullDataToColumnData(level, (FullDataSource) dataSource); + } return null; } diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java b/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java index f966025b9..db9e9935f 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java @@ -3,11 +3,12 @@ package com.seibel.lod.core.a7.datatype.column.render; import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource; import com.seibel.lod.core.a7.datatype.column.accessor.ColumnArrayView; import com.seibel.lod.core.a7.level.IClientLevel; +import com.seibel.lod.core.a7.pos.DhBlockPos2D; +import com.seibel.lod.core.a7.render.a7LodRenderer; import com.seibel.lod.core.a7.util.UncheckedInterruptedException; import com.seibel.lod.core.a7.render.RenderBuffer; import com.seibel.lod.core.config.Config; import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.CubicLodTemplate; -import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodBufferBuilderFactory; import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodQuadBuilder; import com.seibel.lod.core.enums.ELodDirection; import com.seibel.lod.core.enums.config.EGpuUploadMethod; @@ -15,6 +16,7 @@ import com.seibel.lod.core.enums.rendering.EDebugMode; import com.seibel.lod.core.enums.rendering.EGLProxyContext; import com.seibel.lod.core.logging.ConfigBasedLogger; import com.seibel.lod.core.logging.DhLoggerBuilder; +import com.seibel.lod.core.objects.DHBlockPos; import com.seibel.lod.core.render.GLProxy; import com.seibel.lod.core.render.LodRenderProgram; import com.seibel.lod.core.render.objects.GLVertexBuffer; @@ -45,8 +47,10 @@ public class ColumnRenderBuffer extends RenderBuffer { private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); private static final long MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS = 1_000_000; GLVertexBuffer[] vbos; + public final DHBlockPos pos; - public ColumnRenderBuffer() { + public ColumnRenderBuffer(DHBlockPos pos) { + this.pos = pos; vbos = new GLVertexBuffer[0]; } @@ -67,7 +71,7 @@ public class ColumnRenderBuffer extends RenderBuffer { int size = bb.limit() - bb.position(); try { vbo.bind(); - vbo.uploadBuffer(bb, size/LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, LodBufferBuilderFactory.FULL_SIZED_BUFFER); + vbo.uploadBuffer(bb, size/LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, FULL_SIZED_BUFFER); } catch (Exception e) { vbos[i-1] = null; vbo.close(); @@ -136,22 +140,14 @@ public class ColumnRenderBuffer extends RenderBuffer { } @Override - public boolean render(LodRenderProgram shaderProgram) { + public boolean render(a7LodRenderer renderContext) { boolean hasRendered = false; + renderContext.setupOffset(pos); for (GLVertexBuffer vbo : vbos) { if (vbo == null) continue; if (vbo.getVertexCount() == 0) continue; hasRendered = true; - vbo.bind(); - shaderProgram.bindVertexBuffer(vbo.getId()); - //FIXME: Fix this! Need to pass this down - if (/*LodRenderer.ENABLE_IBO*/ true) { - GL32.glDrawElements(GL32.GL_TRIANGLES, (vbo.getVertexCount()/4)*6, - GL32.GL_INT //FIXME: Fix this! Need to pass this as argument down the chains! - , 0); - } else { - GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, vbo.getVertexCount()); - } + renderContext.drawVbo(vbo); //LodRenderer.tickLogger.info("Vertex buffer: {}", vbo); } return hasRendered; @@ -164,7 +160,7 @@ public class ColumnRenderBuffer extends RenderBuffer { for (GLVertexBuffer b : vbos) { if (b == null) continue; statsMap.incStat("VBOs"); - if (b.getSize() == LodBufferBuilderFactory.FULL_SIZED_BUFFER) { + if (b.getSize() == FULL_SIZED_BUFFER) { statsMap.incStat("FullsizedVBOs"); } if (b.getSize() == 0) GL_LOGGER.warn("VBO with size 0"); @@ -211,7 +207,10 @@ public class ColumnRenderBuffer extends RenderBuffer { EGpuUploadMethod method = GLProxy.getInstance().getGpuUploadMethod(); EGLProxyContext oldContext = glProxy.getGlContext(); glProxy.setGlContext(EGLProxyContext.LOD_BUILDER); - ColumnRenderBuffer buffer = usedBuffer!=null ? usedBuffer : new ColumnRenderBuffer(); + ColumnRenderBuffer buffer = usedBuffer!=null ? usedBuffer : + new ColumnRenderBuffer( + new DHBlockPos(data.sectionPos.getCorner().getCorner(), clientLevel.getMinY()) + ); try { buffer.uploadBuffer(builder, method); EVENT_LOGGER.trace("RenderRegion end Upload @ {}", data.sectionPos); diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/full/IdBiomeBlockStateMap.java b/src/main/java/com/seibel/lod/core/a7/datatype/full/IdBiomeBlockStateMap.java index 9a54fc3c3..ca90cc527 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/full/IdBiomeBlockStateMap.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/full/IdBiomeBlockStateMap.java @@ -5,7 +5,7 @@ import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper; -import java.io.IOException; +import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.Objects; @@ -77,5 +77,27 @@ public class IdBiomeBlockStateMap { return mapper; } - //TODO: Serialization & Deserialization + void serialize(OutputStream os) { + try (DataOutputStream dos = new DataOutputStream(os)) { + dos.writeInt(entries.size()); + for (Entry e : entries) { + dos.writeUTF(e.serialize()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + static IdBiomeBlockStateMap deserialize(InputStream is) { + try (DataInputStream dis = new DataInputStream(is)) { + int size = dis.readInt(); + IdBiomeBlockStateMap map = new IdBiomeBlockStateMap(); + for (int i = 0; i < size; i++) { + map.entries.add(Entry.deserialize(dis.readUTF())); + } + return map; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } } diff --git a/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java b/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java index 3721d3c12..ad44ea503 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/DhClientLevel.java @@ -11,7 +11,7 @@ import com.seibel.lod.core.config.Config; import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.objects.math.Mat4f; -import com.seibel.lod.core.render.a7LodRenderer; +import com.seibel.lod.core.a7.render.a7LodRenderer; import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper; diff --git a/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java b/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java index 6a2f88a16..56156e4d9 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/DhClientServerLevel.java @@ -11,7 +11,7 @@ import com.seibel.lod.core.config.Config; import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.objects.math.Mat4f; -import com.seibel.lod.core.render.a7LodRenderer; +import com.seibel.lod.core.a7.render.a7LodRenderer; import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper; diff --git a/src/main/java/com/seibel/lod/core/a7/level/DhServerLevel.java b/src/main/java/com/seibel/lod/core/a7/level/DhServerLevel.java index 834d99893..8b6c2e4b1 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/DhServerLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/DhServerLevel.java @@ -1,9 +1,13 @@ package com.seibel.lod.core.a7.level; +import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; +import com.seibel.lod.core.a7.pos.DhBlockPos2D; +import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.util.FileScanner; import com.seibel.lod.core.a7.save.io.file.LocalDataFileHandler; import com.seibel.lod.core.a7.save.structure.LocalSaveStructure; import com.seibel.lod.core.logging.DhLoggerBuilder; +import com.seibel.lod.core.objects.DHChunkPos; import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper; import org.apache.logging.log4j.Logger; @@ -52,6 +56,13 @@ public class DhServerLevel implements IServerLevel { public void doWorldGen() { } + + @Override + public void submitChunkData(DHChunkPos chunkPos, ChunkSizedData data) { + DhSectionPos sectionPos = new DhSectionPos((byte)4, chunkPos.x, chunkPos.z); + dataFileHandler.write(sectionPos, data); + } + @Override public ILevelWrapper getLevelWrapper() { return level; diff --git a/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java b/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java index 844c6a21a..15122031c 100644 --- a/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java +++ b/src/main/java/com/seibel/lod/core/a7/level/IServerLevel.java @@ -1,6 +1,9 @@ package com.seibel.lod.core.a7.level; +import com.seibel.lod.core.a7.datatype.full.ChunkSizedData; + public interface IServerLevel extends ILevel { void serverTick(); void doWorldGen(); + void submitChunkData(ChunkSizedData data); } diff --git a/src/main/java/com/seibel/lod/core/a7/render/RenderBuffer.java b/src/main/java/com/seibel/lod/core/a7/render/RenderBuffer.java index 6a4e8ecb8..e7225921b 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/RenderBuffer.java +++ b/src/main/java/com/seibel/lod/core/a7/render/RenderBuffer.java @@ -20,6 +20,7 @@ package com.seibel.lod.core.a7.render; import com.seibel.lod.core.render.LodRenderProgram; +import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.StatsMap; public abstract class RenderBuffer implements AutoCloseable @@ -31,7 +32,7 @@ public abstract class RenderBuffer implements AutoCloseable // ========== Called by render thread ========== /* Called on... well... rendering. * Return false if nothing rendered. (Optional) */ - public abstract boolean render(LodRenderProgram shaderProgram); + public abstract boolean render(a7LodRenderer renderContext); // ========== Called by any thread. (thread safe) ========== @@ -47,6 +48,14 @@ public abstract class RenderBuffer implements AutoCloseable * thread), or by others when the object is not being used. (not in build, * upload, or render state). */ public abstract void close(); - - + + + + public static final int DEFAULT_MEMORY_ALLOCATION = (LodUtil.LOD_VERTEX_FORMAT.getByteSize() * 3) * 8; + public static final int QUADS_BYTE_SIZE = LodUtil.LOD_VERTEX_FORMAT.getByteSize() * 4; + public static final int MAX_QUADS_PER_BUFFER = (1024 * 1024 * 1) / QUADS_BYTE_SIZE; + public static final int FULL_SIZED_BUFFER = MAX_QUADS_PER_BUFFER * QUADS_BYTE_SIZE; + + + } diff --git a/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java b/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java index 8283750bf..59887e115 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java +++ b/src/main/java/com/seibel/lod/core/a7/render/RenderBufferHandler.java @@ -22,7 +22,7 @@ public class RenderBufferHandler { this.pos = pos; } - public void render(LodRenderProgram renderContext) { + public void render(a7LodRenderer renderContext) { RenderBuffer buff = renderBufferSlot.get(); if (buff != null) { buff.render(renderContext); @@ -109,7 +109,7 @@ public class RenderBufferHandler { renderBufferNodes = new MovableGridRingList<>(referenceList.getHalfSize(), center); } - public void render(LodRenderProgram renderContext) { + public void render(a7LodRenderer renderContext) { //TODO: This might get locked by update() causing move() call. Is there a way to avoid this? // Maybe dupe the base list and use atomic swap on render? Or is this not worth it? //TODO: Directional culling diff --git a/src/main/java/com/seibel/lod/core/render/a7LodRenderer.java b/src/main/java/com/seibel/lod/core/a7/render/a7LodRenderer.java similarity index 95% rename from src/main/java/com/seibel/lod/core/render/a7LodRenderer.java rename to src/main/java/com/seibel/lod/core/a7/render/a7LodRenderer.java index 27868555b..2daa7dae9 100644 --- a/src/main/java/com/seibel/lod/core/render/a7LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/a7/render/a7LodRenderer.java @@ -17,11 +17,10 @@ * along with this program. If not, see . */ -package com.seibel.lod.core.render; +package com.seibel.lod.core.a7.render; import com.seibel.lod.core.a7.level.IClientLevel; import com.seibel.lod.core.config.Config; -import com.seibel.lod.core.builders.lodBuilding.bufferBuilding.LodBufferBuilderFactory; import com.seibel.lod.core.config.types.ConfigEntry; import com.seibel.lod.core.enums.rendering.EDebugMode; import com.seibel.lod.core.enums.rendering.EFogColorMode; @@ -29,11 +28,14 @@ import com.seibel.lod.core.handlers.dependencyInjection.SingletonInjector; import com.seibel.lod.core.logging.ConfigBasedLogger; import com.seibel.lod.core.logging.ConfigBasedSpamLogger; import com.seibel.lod.core.objects.DHBlockPos; -import com.seibel.lod.core.a7.render.RenderBufferHandler; import com.seibel.lod.core.objects.math.Mat4f; import com.seibel.lod.core.objects.math.Vec3d; import com.seibel.lod.core.objects.math.Vec3f; +import com.seibel.lod.core.render.GLProxy; +import com.seibel.lod.core.render.LodFogConfig; +import com.seibel.lod.core.render.LodRenderProgram; import com.seibel.lod.core.render.objects.GLState; +import com.seibel.lod.core.render.objects.GLVertexBuffer; import com.seibel.lod.core.render.objects.QuadElementBuffer; import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; @@ -66,6 +68,18 @@ public class a7LodRenderer public static final long DRAW_LAG_SPIKE_THRESHOLD_NS = TimeUnit.NANOSECONDS.convert(20, TimeUnit.MILLISECONDS); public static final boolean ENABLE_IBO = true; + + public void setupOffset(DHBlockPos pos) { + shaderProgram.setModelPos(new Vec3f(pos.x, pos.y, pos.z)); + } + + public void drawVbo(GLVertexBuffer vbo) { + vbo.bind(); + shaderProgram.bindVertexBuffer(vbo.getId()); + GL32.glDrawElements(GL32.GL_TRIANGLES, (vbo.getVertexCount()/4)*6, + quadIBO.getType(), 0); + } + public static class LagSpikeCatcher { long timer = System.nanoTime(); public LagSpikeCatcher() {} @@ -219,7 +233,7 @@ public class a7LodRenderer int drawCount = 0; //TODO: Directional culling - bufferHandler.render(shaderProgram); + bufferHandler.render(this); //if (drawCall==0) // tickLogger.info("DrawCall Count: {}", drawCount); @@ -267,7 +281,7 @@ public class a7LodRenderer shaderProgram = new LodRenderProgram(LodFogConfig.generateFogConfig()); if (ENABLE_IBO) { quadIBO = new QuadElementBuffer(); - quadIBO.reserve(LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER); + quadIBO.reserve(RenderBuffer.MAX_QUADS_PER_BUFFER); } EVENT_LOGGER.info("Renderer setup complete"); } diff --git a/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphics.java b/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphics.java index f28ca1d6c..86d737131 100644 --- a/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphics.java +++ b/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphics.java @@ -20,7 +20,6 @@ package com.seibel.lod.core.api.external.methods.config.client; import com.seibel.lod.core.api.external.items.interfaces.config.IDhApiConfig; -import com.seibel.lod.core.api.external.methods.config.objects.enums.*; import com.seibel.lod.core.api.external.items.enums.config.*; import com.seibel.lod.core.api.implementation.objects.GenericEnumConverter; import com.seibel.lod.core.api.implementation.objects.RenderModeEnabledConverter; diff --git a/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphicsFog.java b/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphicsFog.java index c06a4bbf1..1c4e33f7a 100644 --- a/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphicsFog.java +++ b/src/main/java/com/seibel/lod/core/api/external/methods/config/client/DhApiGraphicsFog.java @@ -20,7 +20,6 @@ package com.seibel.lod.core.api.external.methods.config.client; import com.seibel.lod.core.api.external.items.interfaces.config.IDhApiConfig; -import com.seibel.lod.core.api.external.methods.config.objects.enums.*; import com.seibel.lod.core.api.external.items.enums.config.*; import com.seibel.lod.core.api.implementation.objects.GenericEnumConverter; import com.seibel.lod.core.api.implementation.wrappers.DhApiConfig; diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java deleted file mode 100644 index c2967b838..000000000 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ /dev/null @@ -1,569 +0,0 @@ -/* - * This file is part of the Distant Horizons mod (formerly the LOD Mod), - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2022 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.lod.core.builders.lodBuilding; - -#if ABC - -import java.util.ConcurrentModificationException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import com.seibel.lod.core.config.Config; -import com.seibel.lod.core.enums.ELodDirection; -import com.seibel.lod.core.enums.config.EBlocksToAvoid; -import com.seibel.lod.core.enums.config.EDistanceGenerationMode; -import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; -import com.seibel.lod.core.logging.ConfigBasedLogger; -import com.seibel.lod.core.objects.DHBlockPos; -import com.seibel.lod.core.objects.lod.LodRegion; -import com.seibel.lod.core.objects.lod.LodWorld; -import com.seibel.lod.core.util.DataPointUtil; -import com.seibel.lod.core.util.DetailDistanceUtil; -import com.seibel.lod.core.util.LevelPosUtil; -import com.seibel.lod.core.util.LodThreadFactory; -import com.seibel.lod.core.util.LodUtil; -import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; -import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper; -import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; -import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; -import com.seibel.lod.core.wrapperInterfaces.world.IDimensionTypeWrapper; -import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper; -import org.apache.logging.log4j.LogManager; - -/** - * This object is in charge of creating Lod related objects. - * - * @author Cola - * @author Leonardo Amato - * @author James Seibel - * @version 12-11-2021 - */ -@SuppressWarnings("GrazieInspection") -public class LodBuilder -{ - private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class); - private static final IWrapperFactory FACTORY = SingletonHandler.get(IWrapperFactory.class); - - public static final ConfigBasedLogger EVENT_LOGGER = new ConfigBasedLogger(LogManager.getLogger(LodBuilder.class), - () -> Config.Client.Advanced.Debugging.DebugSwitch.logLodBuilderEvent.get()); - - /** This cannot be final! Different world have different height, and in menu, this causes Null Exceptions*/ - //public static final short MIN_WORLD_HEIGHT = MC.getWrappedClientWorld().getMinHeight(); - public static short MIN_WORLD_HEIGHT = 0; // Currently modified in EventApi.onWorldLoaded(...) - /** Minecraft's max light value */ - public static final short DEFAULT_MAX_LIGHT = 15; - - //public static final ExecutorService lodGenThreadPool = Executors.newFixedThreadPool(8, new ThreadFactoryBuilder().setNameFormat("Lod-Builder-%d").build()); - - private final ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor( - new LodThreadFactory(this.getClass().getSimpleName(), Thread.NORM_PRIORITY-1)); - - - - /** - * How wide LodDimensions should be in regions
- * Is automatically set before the first frame in ClientProxy. - */ - public int defaultDimensionWidthInRegions = 1; - - //public static final boolean useExperimentalLighting = true; - - - - - public LodBuilder() - { - - } - - public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, boolean genAll) - { - // Block change event - generateLodNodeAsync(chunk, lodWorld, dim, EDistanceGenerationMode.FULL, true, genAll, ()->{}, - ()->{generateLodNodeAsync(chunk,lodWorld,dim, genAll);}); - } - - public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, - EDistanceGenerationMode generationMode, boolean override, boolean genAll, Runnable endCallback, Runnable retryCallback) - { - if (lodWorld == null || lodWorld.getIsWorldNotLoaded()) { - endCallback.run(); - return; - } - // don't try to create an LOD object - // if for some reason we aren't - // given a valid chunk object - if (chunk == null) { - endCallback.run(); - return; - } - - Runnable thread = () -> - { - boolean retryNeeded = false; - try - { - // we need a loaded client world in order to - // get the textures for blocks - if (MC.getWrappedClientWorld() == null) - return; - - // don't try to generate LODs if the user isn't in the world anymore - // (this happens a lot when the user leaves a world/server) - if (!MC.hasSinglePlayerServer() && !MC.connectedToServer()) - return; - - // make sure the dimension exists - // if not, it prob means that player left - LodDimension lodDim = lodWorld.getLodDimension(dim); - if (lodDim == null) return; - - retryNeeded = !generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode), override, genAll); - } - catch (RuntimeException e) - { - EVENT_LOGGER.error("LodBuilder Thread Uncaught Exception: ", e); - // if the world changes while LODs are being generated - // they will throw errors as they try to access things that no longer - // exist. - } finally { - if (!retryNeeded) - endCallback.run(); - else - retryCallback.run(); - } - }; - lodGenThreadPool.execute(thread); - } - - /** - * Creates a LodNode for a chunk in the given world. - * @throws IllegalArgumentException thrown if either the chunk or world is null. - */ - public boolean generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config, boolean override, boolean genAll) - { - try { - if (chunk == null) - throw new IllegalArgumentException("generateLodFromChunk given a null chunk"); - LodRegion region = lodDim.getRegion(chunk.getRegionPosX(), chunk.getRegionPosZ()); - if (region == null) - return false; - // this happens if a LOD is generated after the user leaves the world. - if (MC.getWrappedClientWorld() == null) - return false; - if (!canGenerateLodFromChunk(chunk)) - return false; - - - // generate the LODs - int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte)0); - long[] data = new long[maxVerticalData*16*16]; - boolean isAllVoid = true; - - if (!config.quickFillWithVoid) { - for (int i = 0; i < 16*16; i++) - { - int subX = i/16; - int subZ = i%16; - writeVerticalData(data, i*maxVerticalData, maxVerticalData, chunk, config, subX, subZ); - isAllVoid &= DataPointUtil.isVoid(data[i*maxVerticalData]); - if (!DataPointUtil.doesItExist(data[i*maxVerticalData])) - throw new RuntimeException("writeVerticalData result: Datapoint does not exist at "+ chunk.getMinX()+subX +", "+ chunk.getMinZ()+subZ); - if (DataPointUtil.getGenerationMode(data[i*maxVerticalData]) != config.distanceGenerationMode.complexity) - throw new RuntimeException("writeVerticalData result: Datapoint invalid at "+ chunk.getMinX()+subX +", "+ chunk.getMinZ()+subZ); - } - } else { - for (int i = 0; i < 16*16; i++) - { - data[i*maxVerticalData] = DataPointUtil.createVoidDataPoint(config.distanceGenerationMode.complexity); - } - } - if (isAllVoid) EVENT_LOGGER.debug("The chunk {} is completely void.", chunk); - - // This MUST be done after the data is generated, to ensure that during the generation, the data is valid. - if (!canGenerateLodFromChunk(chunk)) // TODO Why are we calling this again? - James - return false; // Answer: Because concurrency change may cause the chunk to have invalid data, like light. - - if (genAll) { - return writeAllLodNodeData(lodDim, region, chunk.getChunkPosX(), chunk.getChunkPosZ(), data, config, override); - } else { - return writePartialLodNodeData(lodDim, region, chunk.getChunkPosX(), chunk.getChunkPosZ(), data, config, override); - } - } catch (RuntimeException e) { - EVENT_LOGGER.error("LodBuilder encountered an error on building lod: ", e); - return false; - } - } - public static boolean canGenerateLodFromChunk(IChunkWrapper chunk) - { - return chunk != null && chunk.isLightCorrect() && chunk.doesNearbyChunksExist(); - } - - private boolean writeAllLodNodeData(LodDimension lodDim, LodRegion region, int chunkX, int chunkZ, - long[] data, LodBuilderConfig config, boolean override) - { - region.isWriting.incrementAndGet(); - try { - if (region.getMinDetailLevel()!= 0) { - if (!LodUtil.checkRamUsage(0.05, 16)) { - EVENT_LOGGER.debug("LodBuilder: Not enough RAM available for loading files to build lods! Returning..."); - return false; - } - - LodRegion newRegion = lodDim.getRegionFromFile(region, (byte)0, region.getVerticalQuality()); - if (region!=newRegion) - throw new RuntimeException(); - } - //ApiShared.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}", - // chunk.getChunkPosX(), chunk.getChunkPosZ(), chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode); - region.addChunkOfData((byte)0, chunkX*16, chunkZ*16, 16, 16, data, data.length/16/16, override); - region.regenerateLodFromArea((byte)0, chunkX*16, chunkZ*16, 16, 16); - - if (!region.doesDataExist((byte)0, chunkX*16, chunkZ*16, config.distanceGenerationMode)) - throw new RuntimeException("data at detail 0 is still null after writes to it!"); - if (!region.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, chunkZ, config.distanceGenerationMode)) - throw new RuntimeException("data at chunk detail level is still null after writes to it!"); - } finally { - region.isWriting.decrementAndGet(); - } - return true; - } - - private boolean writePartialLodNodeData(LodDimension lodDim, LodRegion region, int chunkX, int chunkZ, - long[] data, LodBuilderConfig config, boolean override) - { - region.isWriting.incrementAndGet(); - try { - byte targetLevel = region.getMinDetailLevel(); - int vertQual = DetailDistanceUtil.getMaxVerticalData(targetLevel); - int lodCount = (targetLevel >= LodUtil.CHUNK_DETAIL_LEVEL) ? - 1 : 1 << (LodUtil.CHUNK_DETAIL_LEVEL - targetLevel); - if (targetLevel != 0) { - int lodWidth = 16/lodCount; - int inputVertQual = data.length/16/16; - long[] mergedData = new long[vertQual*lodCount*lodCount]; - for (int subX=0; subX= chunk.getMinBuildHeight()) { - int height = determineHeightPointFrom(chunk, config, x, y, z); - // If the lod is at the default height, it must be void data - if (height < chunk.getMinBuildHeight()) { - if (topBlock) dataToMerge[0] = DataPointUtil.createVoidDataPoint(generation); - break; - } - y = height - 1; - // We search light on above air block - int depth = determineBottomPointFrom(chunk, config, x, y, z, - count < maxConnectedLods && (!hasCeiling || !topBlock)); - if (hasCeiling && topBlock) - y = depth; - int light = getLightValue(chunk, x, y, z, hasCeiling, hasSkyLight, topBlock); - int color = generateLodColor(chunk, config, x, y, z); - int lightBlock = light & 0b1111; - int lightSky = (light >> 4) & 0b1111; - dataToMerge[count] = DataPointUtil.createDataPoint(height-chunk.getMinBuildHeight(), depth-chunk.getMinBuildHeight(), - color, lightSky, lightBlock, generation); - topBlock = false; - y = depth - 1; - count++; - } - long[] result = DataPointUtil.mergeMultiData(dataToMerge, totalVerticalData, maxVerticalData); - if (result.length != maxVerticalData) throw new ArrayIndexOutOfBoundsException(); - 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 }; - - private boolean hasCliffFace(IChunkWrapper chunk, int x, int y, int z) { - for (ELodDirection dir : DIRECTIONS) { - IBlockDetailWrapper block = chunk.getBlockDetailAtFace(x, y, z, dir); - if (block == null || !block.hasFaceCullingFor(ELodDirection.OPPOSITE_DIRECTIONS[dir.ordinal()])) - return true; - } - return false; - } - - /** - * Find the lowest valid point from the bottom. - * Used when creating a vertical LOD. - */ - private int determineBottomPointFrom(IChunkWrapper chunk, LodBuilderConfig builderConfig, int xAbs, int yAbs, int zAbs, boolean strictEdge) - { - int depth = chunk.getMinBuildHeight(); - IBlockDetailWrapper currentBlockDetail = null; - if (strictEdge) - { - IBlockDetailWrapper blockAbove = chunk.getBlockDetail(xAbs, yAbs + 1, zAbs); - if (blockAbove != null && Config.Client.WorldGenerator.tintWithAvoidedBlocks.get() && !blockAbove.shouldRender(Config.Client.WorldGenerator.blocksToAvoid.get())) - { // The above block is skipped. Lets use its skipped color for current block - currentBlockDetail = blockAbove; - } - if (currentBlockDetail == null) currentBlockDetail = chunk.getBlockDetail(xAbs, yAbs, zAbs); - } - - for (int y = yAbs - 1; y >= chunk.getMinBuildHeight(); y--) - { - IBlockDetailWrapper nextBlock = chunk.getBlockDetail(xAbs, y, zAbs); - if (isLayerValidLodPoint(nextBlock)) { - if (!strictEdge) continue; - if (currentBlockDetail.equals(nextBlock)) continue; - if (!hasCliffFace(chunk, xAbs, y, zAbs)) continue; - } - depth = (y + 1); - break; - } - return depth; - } - - /** Find the highest valid point from the Top */ - private int determineHeightPointFrom(IChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs) - { - //TODO find a way to skip bottom of the world - int height = chunk.getMinBuildHeight()-1; - for (int y = yAbs; y >= chunk.getMinBuildHeight(); y--) - { - if (isLayerValidLodPoint(chunk, xAbs, y, zAbs)) - { - height = (y + 1); - break; - } - } - return height; - } - - - - // =====================// - // constructor helpers // - // =====================// - - /** - * Generate the color for the given chunk using biome water color, foliage - * color, and grass color. - */ - private int generateLodColor(IChunkWrapper chunk, LodBuilderConfig builderConfig, int x, int y, int z) - { - int colorInt; - if (builderConfig.useBiomeColors) - { - // I have no idea why I need to bit shift to the right, but - // if I don't the biomes don't show up correctly. - colorInt = chunk.getBiome(x, y, z).getColorForBiome(x, z); - } - else - { - // if we are skipping non-full and non-solid blocks that means we ignore - // snow, flowers, etc. Get the above block so we can still get the color - // of the snow, flower, etc. that may be above this block - colorInt = 0; - if (chunk.blockPosInsideChunk(x, y+1, z)) { - IBlockDetailWrapper blockAbove = chunk.getBlockDetail(x, y+1, z); - if (blockAbove != null && Config.Client.WorldGenerator.tintWithAvoidedBlocks.get() && !blockAbove.shouldRender(Config.Client.WorldGenerator.blocksToAvoid.get())) - { // The above block is skipped. Lets use its skipped color for current block - colorInt = blockAbove.getAndResolveFaceColor(null, chunk, new DHBlockPos(x, y+1, z)); - } - } - - // override this block's color if there was a block above this - // and we were avoiding non-full/non-solid blocks - if (colorInt == 0) { - IBlockDetailWrapper detail = chunk.getBlockDetail(x, y, z); - colorInt = detail.getAndResolveFaceColor(null, chunk, new DHBlockPos(x, y, z)); - } - } - - return colorInt; - } - - /** Gets the light value for the given block position */ - private int getLightValue(IChunkWrapper chunk, int x, int y, int z, boolean hasCeiling, boolean hasSkyLight, boolean topBlock) - { - int skyLight; - int blockLight; - - int blockBrightness = chunk.getEmittedBrightness(x, y, z); - // get the air block above or below this block - if (hasCeiling && topBlock) - y--; - else - y++; - - blockLight = chunk.getBlockLight(x, y, z); - skyLight = hasSkyLight ? chunk.getSkyLight(x, y, z) : 0; - - if (blockLight == -1 || skyLight == -1) - { - - ILevelWrapper world = MC.getWrappedServerWorld(); - - if (world != null) - { - // server world sky light (always accurate) - blockLight = world.getBlockLight(x, y, z); - - if (topBlock && !hasCeiling && hasSkyLight) - skyLight = DEFAULT_MAX_LIGHT; - else - skyLight = hasSkyLight ? world.getSkyLight(x, y, z) : 0; - - if (!topBlock && skyLight == 15) - { - // we are on predicted terrain, and we don't know what the light here is, - // lets just take a guess - skyLight = 12; - } - } - else - { - world = MC.getWrappedClientWorld(); - if (world == null) - { - blockLight = 0; - skyLight = 12; - } - else - { - // client world sky light (almost never accurate) - blockLight = world.getBlockLight(x, y, z); - // estimate what the lighting should be - if (hasSkyLight || !hasCeiling) - { - if (topBlock) - skyLight = DEFAULT_MAX_LIGHT; - else - { - if (hasSkyLight) - skyLight = world.getSkyLight(x, y, z); - //else - // skyLight = 0; - if (!chunk.isLightCorrect() && (skyLight == 0 || skyLight == 15)) - { - // we don't know what the light here is, - // lets just take a guess - skyLight = 12; - } - } - } - } - } - } - - blockLight = LodUtil.clamp(0, Math.max(blockLight, blockBrightness), DEFAULT_MAX_LIGHT); - return blockLight + (skyLight << 4); - } - - /** Is the block at the given blockPos a valid LOD point? */ - private boolean isLayerValidLodPoint(IBlockDetailWrapper blockDetail) - { - EBlocksToAvoid avoid = Config.Client.WorldGenerator.blocksToAvoid.get(); - return blockDetail != null && blockDetail.shouldRender(avoid); - } - - /** Is the block at the given blockPos a valid LOD point? */ - private boolean isLayerValidLodPoint(IChunkWrapper chunk, int x, int y, int z) - { - EBlocksToAvoid avoid = Config.Client.WorldGenerator.blocksToAvoid.get(); - IBlockDetailWrapper block = chunk.getBlockDetail(x, y, z); - return block != null && block.shouldRender(avoid); - } -} -#endif \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java index e3c4b55cb..151ba2d15 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/bufferBuilding/LodQuadBuilder.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.ListIterator; +import com.seibel.lod.core.a7.render.RenderBuffer; import com.seibel.lod.core.enums.ELodDirection; import com.seibel.lod.core.enums.ELodDirection.Axis; import com.seibel.lod.core.enums.config.EGpuUploadMethod; @@ -34,6 +35,8 @@ import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.util.LodUtil; import org.apache.logging.log4j.Logger; +//TODO: Recheck this class for refactoring + /** * Used to create the quads before they are converted to renderable buffers. * @@ -94,80 +97,16 @@ public class LodQuadBuilder { 0, 0 }, // 3 }, }; - public static final int[][][] DIRECTION_VERTEX_QUAD = new int[][][] - { - // X,Z // - { // UP - { 1, 0 }, // 0 - { 1, 1 }, // 1 - { 0, 1 }, // 2 - - { 1, 0 }, // 0 - { 0, 1 }, // 2 - { 0, 0 }, // 3 - }, - { // DOWN - { 0, 0 }, // 0 - { 0, 1 }, // 1 - { 1, 1 }, // 2 - - { 0, 0 }, // 0 - { 1, 1 }, // 2 - { 1, 0 }, // 3 - }, - - // X,Y // - { // NORTH - { 0, 0 }, // 0 - { 0, 1 }, // 1 - { 1, 1 }, // 2 - - { 0, 0 }, // 0 - { 1, 1 }, // 2 - { 1, 0 }, // 3 - }, - { // SOUTH - { 1, 0 }, // 0 - { 1, 1 }, // 1 - { 0, 1 }, // 2 - - { 1, 0 }, // 0 - { 0, 1 }, // 2 - { 0, 0 }, // 3 - }, - - // Z,Y // - { // WEST - { 0, 0 }, // 0 - { 1, 0 }, // 1 - { 1, 1 }, // 2 - - { 0, 0 }, // 0 - { 1, 1 }, // 2 - { 0, 1 }, // 3 - }, - { // EAST - { 0, 1 }, // 0 - { 1, 1 }, // 1 - { 1, 0 }, // 2 - - { 0, 1 }, // 0 - { 1, 0 }, // 2 - { 0, 0 }, // 3 - }, - }; private int premergeCount = 0; - private final boolean useIBO; - public LodQuadBuilder(boolean enableSkylightCulling, short skyLightCullingBelow, boolean useIBO) + public LodQuadBuilder(boolean enableSkylightCulling, short skyLightCullingBelow) { for (int i = 0; i < 6; i++) quads[i] = new ArrayList<>(); this.skipQuadsWithZeroSkylight = enableSkylightCulling; this.skyLightCullingBelow = skyLightCullingBelow; - this.useIBO = useIBO; } @@ -259,9 +198,9 @@ public class LodQuadBuilder bb.put(a); } - private static void putQuad(boolean useIBO, ByteBuffer bb, BufferQuad quad) + private static void putQuad(ByteBuffer bb, BufferQuad quad) { - int[][] quadBase = useIBO ? DIRECTION_VERTEX_IBO_QUAD[quad.direction.ordinal()] : DIRECTION_VERTEX_QUAD[quad.direction.ordinal()]; + int[][] quadBase = DIRECTION_VERTEX_IBO_QUAD[quad.direction.ordinal()]; short widthEastWest = quad.widthEastWest; short widthNorthSouth = quad.widthNorthSouthOrUpDown; Axis axis = quad.direction.getAxis(); @@ -366,7 +305,7 @@ public class LodQuadBuilder { return new Iterator() { - final ByteBuffer bb = ByteBuffer.allocateDirect(LodBufferBuilderFactory.FULL_SIZED_BUFFER) + final ByteBuffer bb = ByteBuffer.allocateDirect(RenderBuffer.FULL_SIZED_BUFFER) .order(ByteOrder.nativeOrder()); int dir = skipEmpty(0); int quad = 0; @@ -392,7 +331,7 @@ public class LodQuadBuilder return null; } bb.clear(); - bb.limit(LodBufferBuilderFactory.FULL_SIZED_BUFFER); + bb.limit(RenderBuffer.FULL_SIZED_BUFFER); while (bb.hasRemaining() && dir < 6) { writeData(); @@ -411,7 +350,7 @@ public class LodQuadBuilder { break; } - putQuad(useIBO, bb, quads[dir].get(i)); + putQuad(bb, quads[dir].get(i)); } if (i >= quads[dir].size()) @@ -450,26 +389,26 @@ public class LodQuadBuilder } int numOfQuads = _countRemainingQuads(); - if (numOfQuads > LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER) - numOfQuads = LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER; + if (numOfQuads > RenderBuffer.MAX_QUADS_PER_BUFFER) + numOfQuads = RenderBuffer.MAX_QUADS_PER_BUFFER; if (numOfQuads == 0) { vbo.setVertexCount(0); return false; } - ByteBuffer bb = vbo.mapBuffer(numOfQuads * LodBufferBuilderFactory.QUADS_BYTE_SIZE, method, - LodBufferBuilderFactory.FULL_SIZED_BUFFER); + ByteBuffer bb = vbo.mapBuffer(numOfQuads * RenderBuffer.QUADS_BYTE_SIZE, method, + RenderBuffer.FULL_SIZED_BUFFER); if (bb == null) throw new NullPointerException("mapBuffer returned null"); bb.clear(); - bb.limit(numOfQuads * LodBufferBuilderFactory.QUADS_BYTE_SIZE); + bb.limit(numOfQuads * RenderBuffer.QUADS_BYTE_SIZE); while (bb.hasRemaining() && dir < 6) { writeData(bb); } bb.rewind(); vbo.unmapBuffer(); - vbo.setVertexCount(useIBO ? numOfQuads*4 : numOfQuads*6); + vbo.setVertexCount(numOfQuads*4); return dir < 6; } @@ -494,7 +433,7 @@ public class LodQuadBuilder { break; } - putQuad(useIBO, bb, quads[dir].get(i)); + putQuad(bb, quads[dir].get(i)); } if (i >= quads[dir].size()) @@ -525,7 +464,7 @@ public class LodQuadBuilder /** Returns how many Buffers will be needed to render everything in this builder. */ public int getCurrentNeededVertexBufferCount() { - return LodUtil.ceilDiv(getCurrentQuadsCount(), LodBufferBuilderFactory.MAX_QUADS_PER_BUFFER); + return LodUtil.ceilDiv(getCurrentQuadsCount(), RenderBuffer.MAX_QUADS_PER_BUFFER); } } diff --git a/src/main/java/com/seibel/lod/core/config/file/ConfigFileHandling.java b/src/main/java/com/seibel/lod/core/config/file/ConfigFileHandling.java index d2f6e11a6..8a0229b58 100644 --- a/src/main/java/com/seibel/lod/core/config/file/ConfigFileHandling.java +++ b/src/main/java/com/seibel/lod/core/config/file/ConfigFileHandling.java @@ -24,7 +24,8 @@ import java.nio.file.Path; * @version 2022-5-26 */ public class ConfigFileHandling { - public static final Path ConfigPath = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class).getInstallationDirectory().toPath().resolve("config").resolve(ModInfo.NAME+".toml"); + public static final Path ConfigPath = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class) + .getInstallationDirectory().toPath().resolve("config").resolve(ModInfo.NAME+".toml"); /** Saves the config to the file */ public static void saveToFile() { diff --git a/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/DependencyInjector.java b/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/DependencyInjector.java index 918737e42..abb4124e3 100644 --- a/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/DependencyInjector.java +++ b/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/DependencyInjector.java @@ -147,7 +147,7 @@ public class DependencyInjector * @see #get(Class, boolean) */ @SuppressWarnings("unchecked") - public T get(Class interfaceClass) throws ClassCastException + public T get(Class interfaceClass) throws ClassCastException { return (T) getInternalLogic(interfaceClass, false).get(0); } diff --git a/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/OverrideInjector.java b/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/OverrideInjector.java index d307852a8..8d4ca3658 100644 --- a/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/OverrideInjector.java +++ b/src/main/java/com/seibel/lod/core/handlers/dependencyInjection/OverrideInjector.java @@ -103,7 +103,7 @@ public class OverrideInjector * * @see DependencyInjector#get(Class, boolean) */ - public T get(Class interfaceClass) throws ClassCastException + public T get(Class interfaceClass) throws ClassCastException { T value = primaryInjector.get(interfaceClass); if (value == null) @@ -126,7 +126,7 @@ public class OverrideInjector * * @see DependencyInjector#get(Class, boolean) */ - public T get(Class interfaceClass, EApiOverridePriority overridePriority) throws ClassCastException + public T get(Class interfaceClass, EApiOverridePriority overridePriority) throws ClassCastException { T value; if (overridePriority == EApiOverridePriority.PRIMARY) diff --git a/src/main/java/com/seibel/lod/core/objects/DHBlockPos.java b/src/main/java/com/seibel/lod/core/objects/DHBlockPos.java index a13a7a2b4..be3d1f3c8 100644 --- a/src/main/java/com/seibel/lod/core/objects/DHBlockPos.java +++ b/src/main/java/com/seibel/lod/core/objects/DHBlockPos.java @@ -19,6 +19,8 @@ package com.seibel.lod.core.objects; +import com.seibel.lod.core.a7.pos.DhBlockPos2D; + import java.util.Objects; public class DHBlockPos { @@ -56,6 +58,10 @@ public class DHBlockPos { this(pos.x, pos.y, pos.z); } + public DHBlockPos(DhBlockPos2D pos, int y) { + this(pos.x, y, pos.z); + } + @Deprecated public int getX() { diff --git a/src/main/java/com/seibel/lod/core/objects/PosToRenderContainer.java b/src/main/java/com/seibel/lod/core/objects/PosToRenderContainer.java deleted file mode 100644 index 90ae2f643..000000000 --- a/src/main/java/com/seibel/lod/core/objects/PosToRenderContainer.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * This file is part of the Distant Horizons mod (formerly the LOD Mod), - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2022 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.lod.core.objects; - -#if abc -import java.lang.invoke.MethodHandles; -import java.util.ArrayList; -import java.util.Arrays; - -import com.seibel.lod.core.api.internal.InternalApiShared; -import com.seibel.lod.core.logging.DhLoggerBuilder; -import com.seibel.lod.core.util.LevelPosUtil; -import com.seibel.lod.core.util.LodUtil; -import org.apache.logging.log4j.Logger; - -/** - * Holds a levelPos that needs to be rendered. - * - * @author Leonardo Amato - * @version 9-18-2021 - */ -public class PosToRenderContainer -{ - private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); - - public byte minDetail; - private int regionPosX; - private int regionPosZ; - private int numberOfPosToRender; - private int[] posToRender; - private byte[][] population; - - static class LodPos { - byte detail; - int posX; - int posZ; - } - - private LodPos[] lodPosList; - - public PosToRenderContainer(byte minDetail, int regionPosX, int regionPosZ) - { - this.minDetail = minDetail; - this.numberOfPosToRender = 0; - this.regionPosX = regionPosX; - this.regionPosZ = regionPosZ; - int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - minDetail); - posToRender = new int[size * size * 3]; - population = new byte[size][size]; - lodPosList = new LodPos[size * size]; - } - - public void addPosToRender(byte detailLevel, int posX, int posZ) - { - // When rapidly changing dimensions the bufferBuilder can cause this, - // James isn't sure why, but this will prevent an exception at - // the very least (while stilling logging the problem). - if (numberOfPosToRender >= posToRender.length) - { - // This is might be due to dimensions having a different width - // when first loading in - LOGGER.error("Unable to addPosToRender. numberOfPosToRender [" + numberOfPosToRender + "] detailLevel [" + detailLevel + "] Pos [" + posX + "," + posZ + "]"); - numberOfPosToRender++; // incrementing so we can see how many pos over the limit we would go - return; - } - - //if(numberOfPosToRender >= posToRender.length) - // posToRender = Arrays.copyOf(posToRender, posToRender.length*2); - lodPosList[numberOfPosToRender] = new LodPos(); - lodPosList[numberOfPosToRender].detail = detailLevel; - lodPosList[numberOfPosToRender].posX = posX; - lodPosList[numberOfPosToRender].posZ = posZ; - //posToRender[numberOfPosToRender * 3] = detailLevel; - //posToRender[numberOfPosToRender * 3 + 1] = posX; - //posToRender[numberOfPosToRender * 3 + 2] = posZ; - numberOfPosToRender++; - population[LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel, posX, minDetail))] - [LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel, posZ, minDetail))] = (byte) (detailLevel + 1); - } - - public boolean contains(byte detailLevel, int posX, int posZ) - { - if (LevelPosUtil.getRegion(detailLevel, posX) == regionPosX && LevelPosUtil.getRegion(detailLevel, posZ) == regionPosZ) - return (population[LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel, posX, minDetail))] - [LevelPosUtil.getRegionModule(minDetail, LevelPosUtil.convert(detailLevel, posZ, minDetail))] == (detailLevel + 1)); - else - return false; - } - - public void clear(byte minDetail, int regionPosX, int regionPosZ) - { - this.numberOfPosToRender = 0; - this.regionPosX = regionPosX; - this.regionPosZ = regionPosZ; - int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - minDetail); - if (this.minDetail == minDetail) - { - Arrays.fill(posToRender, 0); - for (byte[] bytes : population) - Arrays.fill(bytes, (byte) 0); - } - else - { - this.minDetail = minDetail; - posToRender = new int[size * size * 3]; - population = new byte[size][size]; - } - lodPosList = new LodPos[size * size]; - } - - public int getNumberOfPos() - { - return numberOfPosToRender; - } - - public byte getNthDetailLevel(int n) - { - return lodPosList[n].detail; - //return (byte) posToRender[n * 3]; - } - - public int getNthPosX(int n) - { - return lodPosList[n].posX; - //return posToRender[n * 3 + 1]; - } - - public int getNthPosZ(int n) - { - return lodPosList[n].posZ; - //return posToRender[n * 3 + 2]; - } - - public void sort() { - Arrays.sort(lodPosList, 0, numberOfPosToRender, - (a,b) -> { - if (a.detail != b.detail) return a.detail - b.detail; - if (a.posX != b.posX) return a.posX - b.posX; - return a.posZ - b.posZ; - } - ); - } - - @Override - public String toString() - { - - StringBuilder builder = new StringBuilder(); - builder.append("To render "); - builder.append(numberOfPosToRender); - builder.append('\n'); - for (int i = 0; i < numberOfPosToRender; i++) - { - builder.append(posToRender[i * 3]); - builder.append(" "); - builder.append(posToRender[i * 3 + 1]); - builder.append(" "); - builder.append(posToRender[i * 3 + 2]); - builder.append('\n'); - } - builder.append('\n'); - return builder.toString(); - } -} -#endif \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java index 53f39e13f..4027e1da1 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java @@ -318,17 +318,7 @@ public class LodRegion { } return (byte) Math.max(getMinDetailLevel(), renderLevel); } - - public void getPosToRender(PosToRenderContainer posToRender, int playerPosX, - int playerPosZ) - { - // use FAR_FIRST on local worlds and NEAR_FIRST on servers - EGenerationPriority generationPriority = getResolvedGenerationPriority(); - EDropoffQuality dropoffQuality = CONFIG.client().graphics().quality().getResolvedDropoffQuality(); - - getPosToRender(posToRender, playerPosX, playerPosZ, generationPriority, dropoffQuality); - } private EGenerationPriority getResolvedGenerationPriority() { EGenerationPriority priority = Config.Client.WorldGenerator.generationPriority.get(); @@ -346,140 +336,7 @@ public class LodRegion { return dropoffQuality; } - /** - * This method will fill the posToRender array with all levelPos that are - * render-able. - *

- * TODO why don't we return the posToRender, it would make this easier to - * understand - */ - private void getPosToRender(PosToRenderContainer posToRender, int playerPosX, int playerPosZ, - EGenerationPriority priority, EDropoffQuality dropoffQuality) { - double minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ); - byte targetLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance); - if (targetLevel <= dropoffQuality.fastModeSwitch) { - getPosToRender(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerPosX, playerPosZ, - priority); - } else { - // FarModeSwitchLevel or above is the level where a giant block of lod is not acceptable even if not all child data exist. - double centerDistance = LevelPosUtil.centerDistance(LodUtil.REGION_DETAIL_LEVEL, regionPosX, regionPosZ, playerPosX, playerPosZ); - targetLevel = DetailDistanceUtil.getDetailLevelFromDistance(centerDistance); - byte farModeSwitchLevel = (priority == EGenerationPriority.NEAR_FIRST) ? 0 : - calculateFarModeSwitch(targetLevel); - if (priority == EGenerationPriority.FAR_FIRST) farModeSwitchLevel = 8; - getPosToRenderFlat(posToRender, LodUtil.REGION_DETAIL_LEVEL, 0, 0, targetLevel, farModeSwitchLevel); - } - } - /** - * This method will fill the posToRender array with all levelPos that are - * render-able. - *

- * TODO why don't we return the posToRender, it would make this easier to - * understand TODO this needs some more comments, James was only able to figure - * out part of it - */ - private void getPosToRender(PosToRenderContainer posToRender, byte detailLevel, int offsetPosX, int offsetPosZ, int playerPosX, - int playerPosZ, EGenerationPriority priority) { - // equivalent to 2^(...) - int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); - - // calculate the LevelPos that are in range - double minDistance = LevelPosUtil.minDistance(detailLevel, offsetPosX + regionPosX*size, offsetPosZ + regionPosZ*size, playerPosX, playerPosZ); - byte minLevel = DetailDistanceUtil.getDetailLevelFromDistance(minDistance); - // FarModeSwitchLevel or above is the level where a giant block of lod is not acceptable even if not all child data exist. - byte farModeSwitchLevel = (priority == EGenerationPriority.NEAR_FIRST) ? 0 : calculateFarModeSwitch(minLevel); - if (priority == EGenerationPriority.FAR_FIRST) farModeSwitchLevel = 8; - - if (detailLevel <= minLevel) { - posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size); - } else // case where (detailLevel > desiredLevel) - { - int childPosX = (offsetPosX + regionPosX*size) * 2; - int childPosZ = (offsetPosZ + regionPosZ*size) * 2; - byte childDetailLevel = (byte) (detailLevel - 1); - - if (detailLevel > farModeSwitchLevel) { - // Giant block is not acceptable. So leave empty void if data doesn't exist. - for (int x = 0; x <= 1; x++) { - for (int z = 0; z <= 1; z++) { - if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, EDistanceGenerationMode.NONE)) { - getPosToRender(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, playerPosX, - playerPosZ, priority); - } - } - } - } else { - // Giant block is acceptable. So use this level lod if not all child data exist. - int childrenCount = 0; - for (int x = 0; x <= 1; x++) { - for (int z = 0; z <= 1; z++) { - if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, EDistanceGenerationMode.NONE)) { - childrenCount++; - } - } - } - // If all the four children exist go deeper - if (childrenCount == 4) { - for (int x = 0; x <= 1; x++) - for (int z = 0; z <= 1; z++) - getPosToRender(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, playerPosX, - playerPosZ, priority); - } else { - posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size); - } - } - } - } - - /** - * This method will fill the posToRender array with all levelPos that are render-able, - * but the entire region try to use the same detail level. - */ - private void getPosToRenderFlat(PosToRenderContainer posToRender, byte detailLevel, int offsetPosX, int offsetPosZ, - byte targetLevel, byte farModeSwitchLevel) { - // equivalent to 2^(...) - int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); - if (detailLevel == targetLevel) { - posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size); - } else // case where (detailLevel > desiredLevel) - { - int childPosX = (offsetPosX + regionPosX*size) * 2; - int childPosZ = (offsetPosZ + regionPosZ*size) * 2; - byte childDetailLevel = (byte) (detailLevel - 1); - - if (detailLevel > farModeSwitchLevel) { - // Giant block is not acceptable. So leave empty void if data doesn't exist. - for (int x = 0; x <= 1; x++) { - for (int z = 0; z <= 1; z++) { - if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, EDistanceGenerationMode.NONE)) { - getPosToRenderFlat(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, targetLevel, farModeSwitchLevel); - } - } - } - } else { - // Giant block is acceptable. So use this level lod if not all child data exist. - int childrenCount = 0; - for (int x = 0; x <= 1; x++) { - for (int z = 0; z <= 1; z++) { - if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, EDistanceGenerationMode.RENDERABLE)) { - childrenCount++; - } - } - } - // If all the four children exist go deeper - if (childrenCount == 4) { - for (int x = 0; x <= 1; x++) - for (int z = 0; z <= 1; z++) - getPosToRenderFlat(posToRender, childDetailLevel, offsetPosX*2 + x, offsetPosZ*2 + z, targetLevel, farModeSwitchLevel); - } else { - posToRender.addPosToRender(detailLevel, offsetPosX + regionPosX * size, offsetPosZ + regionPosZ * size); - } - } - } - } - - public static final class LevelPos { public final byte detail; public final int posX;