From c1309eb4e87c9bcce02ee6f41d33a8fd60bc92a5 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 16 Dec 2023 15:44:29 -0600 Subject: [PATCH 1/5] Add IDhApiWrapperFactory --- .../com/seibel/distanthorizons/api/DhApi.java | 7 ++ .../factories/IDhApiWrapperFactory.java | 80 +++++++++++++++++++ .../worldGenerator/IDhApiWorldGenerator.java | 14 +++- .../distanthorizons/core/Initializer.java | 7 ++ .../wrapperInterfaces/IWrapperFactory.java | 3 +- 5 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java diff --git a/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java b/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java index a069e5da3..1597a3587 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java @@ -20,6 +20,7 @@ package com.seibel.distanthorizons.api; import com.seibel.distanthorizons.api.interfaces.events.IDhApiEventInjector; +import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory; import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGeneratorOverrideRegister; import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy; @@ -114,6 +115,12 @@ public class DhApi */ public static IDhApiRenderProxy renderProxy = null; + /** + * Used to create wrappers for Minecraft objects needed by other Distant Horizons API methods. + * @since API 1.1.0 + */ + public static IDhApiWrapperFactory wrapperFactory = null; + } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java new file mode 100644 index 000000000..85dd509a2 --- /dev/null +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java @@ -0,0 +1,80 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 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.distanthorizons.api.interfaces.factories; + +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; +import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; +import com.seibel.distanthorizons.api.DhApi; + +import java.io.IOException; + +/** + * This handles creating abstract wrapper objects. + * + * @author James Seibel + * @version 2023-12-16 + * @since API 1.1.0 + */ +public interface IDhApiWrapperFactory +{ + /** + * Constructs a {@link IDhApiBiomeWrapper} for use by other DhApi methods. + * + * @param objectArray Expects the following Minecraft objects (in order) for each MC version:
+ * 1.16 and 1.17
+ * - [net.minecraft.world.level.biome.Biome]
+ * 1.18 and newer
+ * - {@literal [net.minecraft.core.Holder] }
+ * + * @param levelWrapper Expects a {@link IDhApiLevelWrapper} returned by one of DH's {@link DhApi.Delayed#worldProxy} methods.
+ * A custom implementation of {@link IDhApiLevelWrapper} will not be accepted. + * + * @throws ClassCastException if any of the given parameters is of the wrong type. + * If thrown the error message will contain the list of expected object types in order. + * + * @since API 1.1.0 + */ + IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper) throws ClassCastException; + + /** + * Constructs a {@link IDhApiBlockStateWrapper} for use by other DhApi methods. + * + * @param objectArray Expects the following Minecraft objects (in order) for each MC version:
+ * 1.16 and newer
+ * - [net.minecraft.world.level.block.state.BlockState]
+ * + * @param levelWrapper Expects a {@link IDhApiBlockStateWrapper} returned by one of DH's {@link DhApi.Delayed#worldProxy} methods.
+ * A custom implementation of {@link IDhApiBlockStateWrapper} will not be accepted. + * + * @throws ClassCastException if any of the given parameters is of the wrong type. + * If thrown the error message will contain the list of expected object types in order. + * + * @since API 1.1.0 + */ + IDhApiBlockStateWrapper getBlockStateWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper) throws ClassCastException; + + /** + * Returns the {@link IDhApiBlockStateWrapper} representing air. + * @since API 1.1.0 + */ + IDhApiBlockStateWrapper getAirBlockStateWrapper(); + +} diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java index 3070c8511..5ec1293f0 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java @@ -48,6 +48,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable * TODO: System currently only supports 1x1 block per data. * * @see EDhApiDetailLevel + * @since API 1.0.0 */ default byte getSmallestDataDetailLevel() { return EDhApiDetailLevel.BLOCK.detailLevel; } /** @@ -57,6 +58,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable * For more information on what detail levels represent see: {@link EDhApiDetailLevel}. * * @see EDhApiDetailLevel + * @since API 1.0.0 */ default byte getLargestDataDetailLevel() { return EDhApiDetailLevel.BLOCK.detailLevel; } @@ -69,6 +71,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable * For more information on what detail levels represent see: {@link EDhApiDetailLevel}. * * @see EDhApiDetailLevel + * @since API 1.0.0 */ default byte getMinGenerationGranularity() { return EDhApiDetailLevel.CHUNK.detailLevel; } @@ -81,10 +84,14 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable * For more information on what detail levels represent see: {@link EDhApiDetailLevel}. * * @see EDhApiDetailLevel + * @since API 1.0.0 */ default byte getMaxGenerationGranularity() { return (byte) (EDhApiDetailLevel.CHUNK.detailLevel + 2); } - /** @return true if the generator is unable to accept new generation requests. */ + /** + * @return true if the generator is unable to accept new generation requests. + * @since API 1.0.0 + */ boolean isBusy(); @@ -115,7 +122,10 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable * @param generatorMode how far into the world gen pipeline this method run. See {@link EDhApiDistantGeneratorMode} for additional documentation. * @param worldGeneratorThreadPool the thread pool that should be used when generating the returned {@link CompletableFuture}. * @param resultConsumer the consumer that should be fired whenever a chunk finishes generating. + * * @return a future that should run on the worldGeneratorThreadPool and complete once the given generation task has completed. + * + * @since API 1.0.0 */ CompletableFuture generateChunks( int chunkPosMinX, int chunkPosMinZ, @@ -131,6 +141,8 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable /** * Called before a new generator task is started.
* This can be used to run cleanup on existing tasks before new tasks are started. + * + * @since API 1.0.0 */ void preGeneratorTaskStart(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java b/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java index c6b34eac1..f5b8bc046 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java @@ -19,7 +19,9 @@ package com.seibel.distanthorizons.core; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.file.DataSourceReferenceTracker; +import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.core.world.DhApiWorldProxy; import com.seibel.distanthorizons.core.api.external.methods.config.DhApiConfig; @@ -67,6 +69,11 @@ public class Initializer DhApi.Delayed.terrainRepo = DhApiTerrainDataRepo.INSTANCE; DhApi.Delayed.worldProxy = DhApiWorldProxy.INSTANCE; DhApi.Delayed.renderProxy = DhApiRenderProxy.INSTANCE; + DhApi.Delayed.wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class); + if (DhApi.Delayed.wrapperFactory == null) + { + LOGGER.error("Programmer Error: No ["+IWrapperFactory.class.getSimpleName()+"] assigned to the DhApi."); + } DataSourceReferenceTracker.startGarbageCollectorBackgroundThread(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java index 6090d3dc0..651b9a231 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core.wrapperInterfaces; +import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; @@ -36,7 +37,7 @@ import java.util.HashSet; * @author James Seibel * @version 2022-12-5 */ -public interface IWrapperFactory extends IBindable +public interface IWrapperFactory extends IDhApiWrapperFactory, IBindable { AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel); IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException; From 1d88d12632797e9965e5a8aacced2c2227d3b79f Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 16 Dec 2023 17:49:28 -0600 Subject: [PATCH 2/5] Fix RenderUtil deprecated warning --- .../com/seibel/distanthorizons/core/util/RenderUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java index 5411e8057..d3cbd2097 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java @@ -19,7 +19,6 @@ package com.seibel.distanthorizons.core.util; -import com.seibel.distanthorizons.api.enums.config.EOverdrawPrevention; import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; @@ -47,6 +46,7 @@ public class RenderUtil private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + //=================// // culling methods // //=================// @@ -62,7 +62,7 @@ public class RenderUtil && pos.x <= center.x + MC_RENDER.getRenderDistance()) && (pos.z >= center.z - MC_RENDER.getRenderDistance() - && pos.z <= center.z + MC_RENDER.getRenderDistance()); + && pos.z <= center.z + MC_RENDER.getRenderDistance()); } /** @@ -76,7 +76,7 @@ public class RenderUtil && x <= centerCoordinate + MC_RENDER.getRenderDistance()) && (z >= centerCoordinate - MC_RENDER.getRenderDistance() - && z <= centerCoordinate + MC_RENDER.getRenderDistance()); + && z <= centerCoordinate + MC_RENDER.getRenderDistance()); } /** @@ -91,7 +91,7 @@ public class RenderUtil && i <= lodRadius + halfRadius) && (j >= lodRadius - halfRadius - && j <= lodRadius + halfRadius); + && j <= lodRadius + halfRadius); } /** From 8dbeb16f33fd7294f85b881ae9ab6ca84077c6aa Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 19 Dec 2023 07:18:23 -0600 Subject: [PATCH 3/5] update several comments --- .../main/java/com/seibel/distanthorizons/api/DhApi.java | 2 +- .../api/interfaces/factories/IDhApiWrapperFactory.java | 9 +++++++++ .../fullData/accessor/SingleColumnFullDataAccessor.java | 8 ++++++++ .../distanthorizons/core/level/DhClientServerLevel.java | 5 +---- .../com/seibel/distanthorizons/core/level/DhLevel.java | 5 +---- .../seibel/distanthorizons/core/level/DhServerLevel.java | 5 +---- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java b/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java index 1597a3587..45eac51f3 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java @@ -46,7 +46,7 @@ import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverri * the concrete object we replaced, there would be issues. * * @author James Seibel - * @version 2023-8-26 + * @version 2023-12-16 * @since API 1.0.0 */ public class DhApi diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java index 85dd509a2..d8dd81ffa 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/factories/IDhApiWrapperFactory.java @@ -77,4 +77,13 @@ public interface IDhApiWrapperFactory */ IDhApiBlockStateWrapper getAirBlockStateWrapper(); + + + ///** + // * Specifically designed to be used with the API. + // * + // * @throws ClassCastException with instructions on expected objects if the object couldn't be cast + // */ + //IChunkWrapper createChunkWrapper(Object[] objectArray) throws ClassCastException; + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/SingleColumnFullDataAccessor.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/SingleColumnFullDataAccessor.java index c26c4f23e..7fde6050c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/SingleColumnFullDataAccessor.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/SingleColumnFullDataAccessor.java @@ -43,6 +43,10 @@ public class SingleColumnFullDataAccessor implements IFullDataAccessor + //=============// + // constructor // + //=============// + public SingleColumnFullDataAccessor(FullDataPointIdMap mapping, long[][] dataArrays, int dataArrayIndex) { this.dataArrays = dataArrays; @@ -54,6 +58,10 @@ public class SingleColumnFullDataAccessor implements IFullDataAccessor + //=========// + // methods // + //=========// + /** @return true if any data exists in this column. */ public boolean doesColumnExist() { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java index 1edae45a5..1d10bbe84 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java @@ -172,10 +172,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS public boolean hasSkyLight() { return this.serverLevelWrapper.hasSkyLight(); } @Override - public void saveWrites(ChunkSizedFullDataAccessor data) - { - clientside.writeChunkDataToFile(data); - } + public void saveWrites(ChunkSizedFullDataAccessor data) { this.clientside.writeChunkDataToFile(data); } @Override public int getMinY() { return getLevelWrapper().getMinHeight(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java index 392693047..b42266214 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java @@ -38,10 +38,7 @@ public abstract class DhLevel implements IDhLevel @Override - public int getMinY() - { - return 0; - } + public int getMinY() { return 0; } @Override public void updateChunkAsync(IChunkWrapper chunk) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index dd9bb218f..fdd34567c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -49,10 +49,7 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel LOGGER.info("Started DHLevel for {} with saves at {}", serverLevelWrapper, saveStructure); } - public void serverTick() - { - chunkToLodBuilder.tick(); - } + public void serverTick() { this.chunkToLodBuilder.tick(); } @Override public void saveWrites(ChunkSizedFullDataAccessor data) From 0caf164e06de78447a091a9bef20b03aef771e44 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 20 Dec 2023 07:47:45 -0600 Subject: [PATCH 4/5] Fix EConfigEntryAppearance.ONLY_IN_FILE --- .../core/config/types/enums/EConfigEntryAppearance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/enums/EConfigEntryAppearance.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/enums/EConfigEntryAppearance.java index 24dd3fd51..6366f57b0 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/enums/EConfigEntryAppearance.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/enums/EConfigEntryAppearance.java @@ -32,7 +32,7 @@ public enum EConfigEntryAppearance /** Will only show the option in the UI. The option will be reverted on game restart */ ONLY_IN_GUI(true, false), /** Only show the option in the file. There would be no way to access it using the UI */ - ONLY_IN_FILE(true, false), + ONLY_IN_FILE(false, true), /** The option is only available via code. Generally this is only used for deprecated options. */ ONLY_IN_API(false, false); From f65b4205c3949428b42de69de16ba6a0822d1b79 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 20 Dec 2023 22:05:58 -0600 Subject: [PATCH 5/5] Potential fix for world gen lockup if files system fails --- .../GeneratedFullDataFileHandler.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 1fc114b3e..cd8215bfa 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -271,16 +271,33 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler else if (genTaskResult.success) { // generation completed, update the files and listener(s) - this.flushAndSaveAsync(pos).join(); - // FIXME this is a bad fix to prevent full data sources saving incomplete, causing holes in the world after generation. - // The problem appears to be that the save may be happening too quickly, - // potentially happening before the meta file has the newly generated data added to it. - CHUNK_GEN_FINISHED_TIMER.schedule(new TimerTask() + try { - @Override - public void run() { GeneratedFullDataFileHandler.this.flushAndSaveAsync(pos).join(); } - }, 4000L); + // timeout necessary in case the flush gets stuck or there are issues down stream + // otherwise the world gen might get stuck and never finish + this.flushAndSaveAsync(pos).get(10_000, TimeUnit.MILLISECONDS); + + + // FIXME this is a bad fix to prevent full data sources saving incompletely, causing holes in the world after generation. + // The problem appears to be that the save may be happening too quickly, + // potentially happening before the meta file has the newly generated data added to it. + CHUNK_GEN_FINISHED_TIMER.schedule(new TimerTask() + { + @Override + public void run() { GeneratedFullDataFileHandler.this.flushAndSaveAsync(pos); } + }, 4_000L); + + } + catch (InterruptedException | TimeoutException e) + { + LOGGER.warn("Unable to flush and save after waiting [10] seconds. Error: "+e.getMessage(), e); + } + catch (ExecutionException e) + { + LOGGER.error("Unexpected issue saving world gen result. Error: "+e.getMessage(), e); + } + this.fireOnGenPosSuccessListeners(pos); return;