From 1ebad39fc1f0d5c97e73c771a279b238df3495b9 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 7 Oct 2024 19:45:33 -0500 Subject: [PATCH] Update the API to allow for N-sized world generation requests This breaks old world generators --- .../worldGeneration/GenerationEvent.java | 6 - coreSubProjects | 2 +- ...ator.java => TestChunkWorldGenerator.java} | 11 +- .../testing/TestGenericWorldGenerator.java | 189 ++++++++++++++++++ .../testing/TestWorldGenBindingEvent.java | 23 ++- 5 files changed, 211 insertions(+), 20 deletions(-) rename fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/{TestWorldGenerator.java => TestChunkWorldGenerator.java} (90%) create mode 100644 fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestGenericWorldGenerator.java diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index 39485c04b..daa8de2ed 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -74,12 +74,6 @@ public final class GenerationEvent EDhApiWorldGenerationStep target, Consumer resultConsumer, ExecutorService worldGeneratorThreadPool) { - //if (size % 2 == 0) - //{ - // size += 1; // size must be odd for vanilla world gen regions to work - //} - - GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, target, resultConsumer); generationEvent.future = CompletableFuture.runAsync(() -> { diff --git a/coreSubProjects b/coreSubProjects index 0b49d1a00..1b59a269e 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 0b49d1a007f8c35f03fe40448e29776e7a46ee47 +Subproject commit 1b59a269e6aaaeb1a6fbbf1ed5c33f542f2f06a3 diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestWorldGenerator.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestChunkWorldGenerator.java similarity index 90% rename from fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestWorldGenerator.java rename to fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestChunkWorldGenerator.java index fe4a59b55..1b0060ca3 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestWorldGenerator.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestChunkWorldGenerator.java @@ -9,17 +9,16 @@ import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.Abstrac import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; import com.seibel.distanthorizons.api.objects.data.DhApiChunk; import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint; -import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; -import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.chunk.ChunkAccess; +import org.apache.logging.log4j.Logger; import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; -public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator +public class TestChunkWorldGenerator extends AbstractDhApiChunkWorldGenerator { private final ServerLevel level; private final IDhApiLevelWrapper levelWrapper; @@ -30,7 +29,7 @@ public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator // constructor // //=============// - public TestWorldGenerator(ServerLevel level) + public TestChunkWorldGenerator(ServerLevel level) { this.level = level; this.levelWrapper = ServerLevelWrapper.getWrapper(level); @@ -46,7 +45,7 @@ public class TestWorldGenerator extends AbstractDhApiChunkWorldGenerator public EDhApiWorldGeneratorReturnType getReturnType() { return EDhApiWorldGeneratorReturnType.API_CHUNKS; } @Override - public boolean runApiChunkValidation() { return true; } + public boolean runApiValidation() { return true; } diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestGenericWorldGenerator.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestGenericWorldGenerator.java new file mode 100644 index 000000000..af2b90683 --- /dev/null +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestGenericWorldGenerator.java @@ -0,0 +1,189 @@ +package com.seibel.distanthorizons.fabric.testing; + +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel; +import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; +import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGeneratorReturnType; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; +import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator; +import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; +import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint; +import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource; +import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import net.minecraft.server.level.ServerLevel; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public class TestGenericWorldGenerator implements IDhApiWorldGenerator +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + + private final IDhApiLevelWrapper levelWrapper; + + + + //=============// + // constructor // + //=============// + + public TestGenericWorldGenerator(IDhApiLevelWrapper levelWrapper) + { this.levelWrapper = levelWrapper; } + + + + //============// + // properties // + //============// + + @Override + public byte getSmallestDataDetailLevel() { return (byte) (EDhApiDetailLevel.BLOCK.detailLevel); } + @Override + public byte getLargestDataDetailLevel() { return (byte) (EDhApiDetailLevel.BLOCK.detailLevel + 12); } + + + @Override + public EDhApiWorldGeneratorReturnType getReturnType() { return EDhApiWorldGeneratorReturnType.API_DATA_SOURCES; } + + @Override + public boolean runApiValidation() { return true; } + + + + //==================// + // chunk generation // + //==================// + + @Override + public CompletableFuture generateLod( + int chunkPosMinX, int chunkPosMinZ, + int posX, int posZ, byte detailLevel, + IDhApiFullDataSource pooledFullDataSource, + EDhApiDistantGeneratorMode generatorMode, ExecutorService worldGeneratorThreadPool, + Consumer resultConsumer) + { + return CompletableFuture.runAsync(() -> + { + // this test is only validated for 1.18.2 and up + // (and it is only needed when testing world gen overrides/API chunks, so it isn't normally needed) + #if MC_VER >= MC_1_18_2 + + + IDhApiBiomeWrapper biome; + IDhApiBlockStateWrapper colorBlock; + IDhApiBlockStateWrapper borderBlock; + IDhApiBlockStateWrapper airBlock; + int maxHeight; + try + { + biome = DhApi.Delayed.wrapperFactory.getBiomeWrapper("minecraft:plains", this.levelWrapper); + airBlock = DhApi.Delayed.wrapperFactory.getAirBlockStateWrapper(); + borderBlock = DhApi.Delayed.wrapperFactory.getDefaultBlockStateWrapper("minecraft:stone", this.levelWrapper); + + String blockResourceLocation; + switch (detailLevel) + { + case 0: + blockResourceLocation = "minecraft:red_wool"; + maxHeight = 60; + break; + case 1: + blockResourceLocation = "minecraft:orange_wool"; + maxHeight = 70; + break; + case 2: + blockResourceLocation = "minecraft:yellow_wool"; + maxHeight = 80; + break; + case 3: + blockResourceLocation = "minecraft:lime_wool"; + maxHeight = 90; + break; + case 4: + blockResourceLocation = "minecraft:cyan_wool"; + maxHeight = 100; + break; + case 5: + blockResourceLocation = "minecraft:blue_wool"; + maxHeight = 100; + break; + case 6: + blockResourceLocation = "minecraft:magenta_wool"; + maxHeight = 110; + break; + case 7: + blockResourceLocation = "minecraft:white_wool"; + maxHeight = 120; + break; + case 8: + blockResourceLocation = "minecraft:gray_wool"; + maxHeight = 120; + break; + default: + blockResourceLocation = "minecraft:black_wool"; + maxHeight = 140; + break; + } + + colorBlock = DhApi.Delayed.wrapperFactory.getDefaultBlockStateWrapper(blockResourceLocation, this.levelWrapper); + + } + catch (IOException e) + { + LOGGER.error("Failed to get biome/block: "+ e.getMessage(), e); + return; + } + + ArrayList dataPoints = new ArrayList<>(); + int width = pooledFullDataSource.getWidthInDataColumns(); + for (int x = 0; x < width; x++) + { + for (int z = 0; z < width; z++) + { + dataPoints.clear(); + + IDhApiBlockStateWrapper block = colorBlock; + if (x == 0 || x == (width-1) + || z == 0 || z == (width-1)) + { + block = borderBlock; + } + + // TODO make mutable dataPoint object + // sky lighting can be ignored. DH will auto light the LODs after they've been submitted + // block lighting however will need to be generated here + dataPoints.add(DhApiTerrainDataPoint.create((byte)0, 0, 0, 0, maxHeight, block, biome)); + dataPoints.add(DhApiTerrainDataPoint.create((byte)0, 0, 0, maxHeight, 256, airBlock, biome)); + + pooledFullDataSource.setApiDataPointColumn(x, z, dataPoints); + } + } + + resultConsumer.accept(pooledFullDataSource); + + #else + return null; + #endif + }, worldGeneratorThreadPool); + } + + + @Override + public void preGeneratorTaskStart() { /* do nothing */ } + + + + //=========// + // cleanup // + //=========// + + @Override + public void close() { /* do nothing */ } + +} diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestWorldGenBindingEvent.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestWorldGenBindingEvent.java index 3830ae053..9c7f79225 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestWorldGenBindingEvent.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestWorldGenBindingEvent.java @@ -8,6 +8,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import net.minecraft.server.level.ServerLevel; import org.apache.logging.log4j.Logger; +// TODO add to API example once Builderb0y has given the all-clear public class TestWorldGenBindingEvent extends DhApiLevelLoadEvent { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -17,12 +18,20 @@ public class TestWorldGenBindingEvent extends DhApiLevelLoadEvent { LOGGER.info("DH Level: ["+event.value.levelWrapper.getDimensionType()+"] loaded."); - // Note: whenever you use a wrapper method on a new Minecraft version it is recommended that you - // call wrapper.getClass() to determine which object the API will return before you try casting it. - ServerLevel level = (ServerLevel) event.value.levelWrapper.getWrappedMcObject(); - - // override the core DH world generator for this level - IDhApiWorldGenerator exampleWorldGen = new TestWorldGenerator(level); - DhApi.worldGenOverrides.registerWorldGeneratorOverride(event.value.levelWrapper, exampleWorldGen); + try + { + // Note: whenever you use a wrapper method on a new Minecraft version it is recommended that you + // call wrapper.getClass() to determine which object the API will return before you try casting it. + ServerLevel level = (ServerLevel) event.value.levelWrapper.getWrappedMcObject(); + + // override the core DH world generator for this level + //IDhApiWorldGenerator exampleWorldGen = new TestChunkWorldGenerator(level); + IDhApiWorldGenerator exampleWorldGen = new TestGenericWorldGenerator(event.value.levelWrapper); + DhApi.worldGenOverrides.registerWorldGeneratorOverride(event.value.levelWrapper, exampleWorldGen); + } + catch (ClassCastException e) + { + LOGGER.warn("Unable to add world generator to level wrapper ["+event.value.levelWrapper.getClass()+"] - ["+event.value.levelWrapper.getDimensionType()+"]."); + } } }