From bd569dad2f9885ac00e4e5f4843925c98a05bde7 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 30 Oct 2021 13:22:54 -0500 Subject: [PATCH] porting - test LodWorldGenerator --- .../lod/builders/lodBuilding/LodBuilder.java | 18 +- .../worldGeneration/LodGenWorker.java | 572 +++++++----------- ...rverWorld.java => LodServerLevel.java.DIS} | 50 +- .../worldGeneration/LodWorldGenerator.java | 12 +- .../com/seibel/lod/proxy/ClientProxy.java | 4 +- .../java/com/seibel/lod/util/LodUtil.java | 24 +- .../lod/wrappers/World/BiomeWrapper.java | 24 +- .../lod/wrappers/World/WorldWrapper.java | 17 +- .../resources/META-INF/accesstransformer.cfg | 10 + 9 files changed, 282 insertions(+), 449 deletions(-) rename src/main/java/com/seibel/lod/builders/worldGeneration/{LodServerWorld.java => LodServerLevel.java.DIS} (80%) diff --git a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java index f88518f2e..9b3eb561e 100644 --- a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java @@ -35,20 +35,18 @@ import com.seibel.lod.util.LevelPosUtil; import com.seibel.lod.util.LodThreadFactory; import com.seibel.lod.util.LodUtil; import com.seibel.lod.util.ThreadMapUtil; -import com.seibel.lod.wrappers.Block.BlockPosWrapper; +import com.seibel.lod.wrappers.MinecraftWrapper; import com.seibel.lod.wrappers.Block.BlockColorWrapper; +import com.seibel.lod.wrappers.Block.BlockPosWrapper; import com.seibel.lod.wrappers.Block.BlockShapeWrapper; import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; import com.seibel.lod.wrappers.Chunk.ChunkWrapper; -import com.seibel.lod.wrappers.MinecraftWrapper; - import com.seibel.lod.wrappers.World.BiomeColorWrapper; import com.seibel.lod.wrappers.World.BiomeWrapper; import com.seibel.lod.wrappers.World.WorldWrapper; - -import net.minecraft.world.DimensionType; -import net.minecraft.world.IWorld; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.dimension.DimensionType; /** * This object is in charge of creating Lod related objects. @@ -89,12 +87,12 @@ public class LodBuilder } - public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, IWorld world) + public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, LevelAccessor world) { generateLodNodeAsync(chunk, lodWorld, world, DistanceGenerationMode.SERVER); } - public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, IWorld world, DistanceGenerationMode generationMode) + public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, LevelAccessor world, DistanceGenerationMode generationMode) { if (lodWorld == null || lodWorld.getIsWorldNotLoaded()) return; @@ -387,7 +385,7 @@ public class LodBuilder // 1 means the lighting is a guess int isDefault = 0; - WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerWorld(); + WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerLevel(); int blockBrightness = chunk.getEmittedBrightness(blockPos); // get the air block above or below this block @@ -505,7 +503,7 @@ public class LodBuilder if (blockColorWrapper.hasTint()) { - WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerWorld(); + WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerLevel(); if (world.isEmpty()) { diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java index 7787664e7..59f427ee4 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java @@ -19,14 +19,11 @@ package com.seibel.lod.builders.worldGeneration; -import java.util.ConcurrentModificationException; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.function.Supplier; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.seibel.lod.builders.lodBuilding.LodBuilder; @@ -36,35 +33,19 @@ import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.objects.LodDimension; import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.util.LodUtil; - +import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; import com.seibel.lod.wrappers.Chunk.ChunkWrapper; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.palette.UpgradeData; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.chunk.ChunkPrimer; -import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.gen.ChunkGenerator; -import net.minecraft.world.gen.Heightmap; -import net.minecraft.world.gen.blockstateprovider.WeightedBlockStateProvider; -import net.minecraft.world.gen.feature.BlockClusterFeatureConfig; -import net.minecraft.world.gen.feature.ConfiguredFeature; -import net.minecraft.world.gen.feature.DecoratedFeatureConfig; -import net.minecraft.world.gen.feature.FeatureSpread; -import net.minecraft.world.gen.feature.FeatureSpreadConfig; -import net.minecraft.world.gen.feature.IceAndSnowFeature; -import net.minecraft.world.gen.feature.NoFeatureConfig; -import net.minecraft.world.gen.feature.template.TemplateManager; -import net.minecraft.world.gen.placement.ConfiguredPlacement; -import net.minecraft.world.gen.placement.DecoratedPlacementConfig; -import net.minecraft.world.gen.placement.IPlacementConfig; -import net.minecraft.world.gen.placement.NoiseDependant; -import net.minecraft.world.server.ServerChunkProvider; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.server.ServerWorldLightManager; + +import net.minecraft.core.Registry; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraftforge.common.WorldWorkerManager.IWorker; /** @@ -90,9 +71,9 @@ public class LodGenWorker implements IWorker - public LodGenWorker(ChunkPos newPos, DistanceGenerationMode newGenerationMode, + public LodGenWorker(ChunkPosWrapper newPos, DistanceGenerationMode newGenerationMode, LodBuilder newLodBuilder, - LodDimension newLodDimension, ServerWorld newServerWorld) + LodDimension newLodDimension, ServerLevel newServerLevel) { // just a few sanity checks if (newPos == null) @@ -104,14 +85,14 @@ public class LodGenWorker implements IWorker if (newLodDimension == null) throw new IllegalArgumentException("LodChunkGenThread requires a non-null LodDimension"); - if (newServerWorld == null) - throw new IllegalArgumentException("LodChunkGenThread requires a non-null ServerWorld"); + if (newServerLevel == null) + throw new IllegalArgumentException("LodChunkGenThread requires a non-null ServerLevel"); thread = new LodChunkGenThread(newPos, newGenerationMode, newLodBuilder, - newLodDimension, newServerWorld); + newLodDimension, newServerLevel); } @Override @@ -156,22 +137,22 @@ public class LodGenWorker implements IWorker private static class LodChunkGenThread implements Runnable { - public final ServerWorld serverWorld; + public final ServerLevel serverLevel; public final LodDimension lodDim; public final DistanceGenerationMode generationMode; public final LodBuilder lodBuilder; - private final ChunkPos pos; + private final ChunkPosWrapper pos; - public LodChunkGenThread(ChunkPos newPos, DistanceGenerationMode newGenerationMode, + public LodChunkGenThread(ChunkPosWrapper newPos, DistanceGenerationMode newGenerationMode, LodBuilder newLodBuilder, - LodDimension newLodDimension, ServerWorld newServerWorld) + LodDimension newLodDimension, ServerLevel newServerLevel) { pos = newPos; generationMode = newGenerationMode; lodBuilder = newLodBuilder; lodDim = newLodDimension; - serverWorld = newServerWorld; + serverLevel = newServerLevel; } @Override @@ -182,79 +163,34 @@ public class LodGenWorker implements IWorker // only generate LodChunks if they can // be added to the current LodDimension - /* TODO I must disable this 'if', if I will find a way to replace it */ - if (lodDim.regionIsInRange(pos.x / LodUtil.REGION_WIDTH_IN_CHUNKS, pos.z / LodUtil.REGION_WIDTH_IN_CHUNKS)) + if (lodDim.regionIsInRange(pos.getX() / LodUtil.REGION_WIDTH_IN_CHUNKS, pos.getZ() / LodUtil.REGION_WIDTH_IN_CHUNKS)) { - // - //{ - // lodBuilder.generateLodNodeFromChunk(lodDim, loadedChunk, new LodBuilderConfig(DistanceGenerationMode.SERVER)); - //} - //else - //{ - /* - IChunk loadedChunk = null; - if (lodDim.isChunkPreGenerated(pos.x, pos.z) && LodConfig.CLIENT.worldGenerator.useExperimentalPreGenLoading.get()) - { - // generate a Lod like normal - loadedChunk = ChunkLoader.getChunkFromFile(pos); - if(loadedChunk != null) - lodBuilder.generateLodNodeFromChunk(lodDim, loadedChunk, new LodBuilderConfig(DistanceGenerationMode.SERVER)); - else - { - switch (generationMode) - { - case NONE: - // don't generate - break; - case BIOME_ONLY: - case BIOME_ONLY_SIMULATE_HEIGHT: - // fastest - generateUsingBiomesOnly(); - break; - case SURFACE: - // faster - generateUsingSurface(); - break; - case FEATURES: - // fast - generateUsingFeatures(); - break; - case SERVER: - // very slow - lodBuilder.generateLodNodeFromChunk(lodDim, serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES), new LodBuilderConfig(DistanceGenerationMode.SERVER)); - //generateWithServer(); - break; - } - } - } - else - {*/ - switch (generationMode) - { - case NONE: - // don't generate - break; - case BIOME_ONLY: - case BIOME_ONLY_SIMULATE_HEIGHT: - // fastest - generateUsingBiomesOnly(); - break; - case SURFACE: - // faster - generateUsingSurface(); - break; - case FEATURES: - // fast - generateUsingFeatures(); - break; - case SERVER: - // very slow - generateWithServer(); - break; - } - //} + // TODO test if anything has changed vs MC 1.16.5 + generateWithServer(); - //lodRenderer.regenerateLODsNextFrame(); +// switch (generationMode) +// { +// case NONE: +// // don't generate +// break; +// case BIOME_ONLY: +// case BIOME_ONLY_SIMULATE_HEIGHT: +// // fastest +// generateUsingBiomesOnly(); +// break; +// case SURFACE: +// // faster +// generateUsingSurface(); +// break; +// case FEATURES: +// // fast +// generateUsingFeatures(); +// break; +// case SERVER: +// // very slow +// generateWithServer(); +// break; +// } /* boolean dataExistence = lodDim.doesDataExist(new LevelPos((byte) 3, pos.x, pos.z)); @@ -294,25 +230,25 @@ public class LodGenWorker implements IWorker */ private void generateUsingBiomesOnly() { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); + List chunkList = new LinkedList<>(); + ProtoChunk chunk = new ProtoChunk(pos.getChunkPos(), UpgradeData.EMPTY, serverLevel); chunkList.add(chunk); - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); + ServerChunkCache chunkSource = serverLevel.getChunkSource(); ChunkGenerator chunkGen = chunkSource.generator; // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + //ChunkStatus.EMPTY.generate(serverLevel, chunkGen, serverLevel.getStructureManager(), (ServerLevelLightManager) serverLevel.getLightEngine(), null, chunkList); // override the chunk status, so we can run the next generator stage chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - chunkGen.createBiomes(serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), chunk); + chunkGen.createBiomes(serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), chunk); chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); // generate fake height data for this LOD - int seaLevel = serverWorld.getSeaLevel(); + int seaLevel = serverLevel.getSeaLevel(); boolean simulateHeight = generationMode == DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT; boolean inTheEnd = false; @@ -330,7 +266,7 @@ public class LodGenWorker implements IWorker switch (chunk.getBiomes().getNoiseBiome(x >> 2, seaLevel >> 2, z >> 2).getBiomeCategory()) { case NETHER: - heightmap.setHeight(x, z, serverWorld.getHeight() / 2); + heightmap.setHeight(x, z, serverLevel.getHeight() / 2); break; case EXTREME_HILLS: @@ -403,164 +339,163 @@ public class LodGenWorker implements IWorker } - /** - * takes about 10 - 20 ms - */ - private void generateUsingSurface() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ServerWorldLightManager lightEngine = (ServerWorldLightManager) serverWorld.getLightEngine(); - TemplateManager templateManager = serverWorld.getStructureManager(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - // override the chunk status, so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - chunkGen.createBiomes(serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), chunk); - ChunkStatus.NOISE.generate(serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - ChunkStatus.SURFACE.generate(serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - - // this feature has been proven to be thread safe, - // so we will add it - IceAndSnowFeature snowFeature = new IceAndSnowFeature(NoFeatureConfig.CODEC); - snowFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null); - - - lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(DistanceGenerationMode.SURFACE)); - - /*TODO if we want to use Biome utils and terrain utils for overworld - * lodBuilder.generateLodNodeFromChunk(lodDim, pos ,detailLevel, serverWorld.getSeed());*/ - } - - - /** - * takes about 15 - 20 ms - *

- * Causes concurrentModification Exceptions, - * which could cause instability or world generation bugs - */ - private void generateUsingFeatures() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ServerWorldLightManager lightEngine = (ServerWorldLightManager) serverWorld.getLightEngine(); - TemplateManager templateManager = serverWorld.getStructureManager(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - // override the chunk status, so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - chunkGen.createBiomes(serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), chunk); - ChunkStatus.NOISE.generate(serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - ChunkStatus.SURFACE.generate(serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - - - // get all the biomes in the chunk - HashSet biomes = new HashSet<>(); - for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++) - { - for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++) - { - Biome biome = chunk.getBiomes().getNoiseBiome(x >> 2, serverWorld.getSeaLevel() >> 2, z >> 2); - - // Issue #35 - // For some reason Jungle biomes cause incredible lag - // the features here must be interacting with each other - // in unpredictable ways (specifically tree feature generation). - // When generating Features my CPU usage generally hovers around 30 - 40% - // when generating Jungles it spikes to 100%. - if (biome.getBiomeCategory() != Biome.Category.JUNGLE) - { - // should probably use the heightmap here instead of seaLevel, - // but this seems to get the job done well enough - biomes.add(biome); - } - } - } - - boolean allowUnstableFeatures = LodConfig.CLIENT.worldGenerator.allowUnstableFeatureGeneration.get(); - - // generate all the features related to this chunk. - // this may or may not be thread safe - for (Biome biome : biomes) - { - List>>> featuresForState = biome.generationSettings.features(); - - for (List>> suppliers : featuresForState) - { - for (Supplier> featureSupplier : suppliers) - { - ConfiguredFeature configuredFeature = featureSupplier.get(); - - if (!allowUnstableFeatures && - configuredFeaturesToAvoid.containsKey(configuredFeature.hashCode())) - continue; - - - try - { - configuredFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition()); - } - catch (ConcurrentModificationException e) - { - // This will happen. I'm not sure what to do about it - // except pray that it doesn't affect the normal world generation - // in any harmful way. - // Update: this can cause crashes and high CPU usage. - - // Issue #35 - // I tried cloning the config for each feature, but that - // path was blocked since I can't clone lambda methods. - // I tried using a deep cloning library and discovered - // the problem there. - // ( https://github.com/kostaskougios/cloning - // and - // https://github.com/EsotericSoftware/kryo ) - - if (!allowUnstableFeatures) - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - catch (UnsupportedOperationException e) - { - // This will happen when the LodServerWorld - // isn't able to return something that a feature - // generator needs - - if (!allowUnstableFeatures) - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - catch (Exception e) - { - // I'm not sure what happened, print to the log - - e.printStackTrace(); - - if (!allowUnstableFeatures) - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - } - } - } - - // generate a Lod like normal - lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(DistanceGenerationMode.FEATURES)); - } +// /** +// * takes about 10 - 20 ms +// */ +// private void generateUsingSurface() +// { +// List chunkList = new LinkedList<>(); +// ProtoChunk chunk = new ProtoChunk(pos.getChunkPos(), UpgradeData.EMPTY, serverLevel); +// chunkList.add(chunk); +// //LodServerLevel lodServerLevel = new LodServerLevel(serverLevel, chunk); +// +// ServerChunkCache chunkSource = serverLevel.getChunkSource(); +// ChunkGenerator chunkGen = chunkSource.generator; +// +// LevelLightEngine lightEngine = serverLevel.getLightEngine(); +// StructureManager templateManager = serverLevel.getStructureManager(); +// +// +// // generate the terrain (this is thread safe) +// //ChunkStatus.EMPTY.generate(serverLevel, chunkGen, templateManager, lightEngine, null, chunkList); +// // override the chunk status, so we can run the next generator stage +// chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); +// chunkGen.createBiomes(serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), chunk); +// ChunkStatus.NOISE.generate(serverLevel, chunkGen, templateManager, lightEngine, null, chunkList); +// ChunkStatus.SURFACE.generate(serverLevel, chunkGen, templateManager, lightEngine, null, chunkList); +// +// // this feature has been proven to be thread safe, +// // so we will add it +// SnowAndFreezeFeature snowFeature = new SnowAndFreezeFeature(NoneFeatureConfiguration.CODEC); +// snowFeature.place(serverLevel, chunkGen, serverLevel.random, chunk.getPos().getWorldPosition(), null); +// +// +// lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(DistanceGenerationMode.SURFACE)); +// } +// +// +// /** +// * takes about 15 - 20 ms +// *

+// * Causes concurrentModification Exceptions, +// * which could cause instability or world generation bugs +// */ +// private void generateUsingFeatures() +// { +// List chunkList = new LinkedList<>(); +// ProtoChunk chunk = new ProtoChunk(pos.getChunkPos(), UpgradeData.EMPTY, serverLevel); +// chunkList.add(chunk); +// LodServerLevel lodServerLevel = new LodServerLevel(serverLevel, chunk); +// +// ServerChunkCache chunkSource = serverLevel.getChunkSource(); +// ChunkGenerator chunkGen = chunkSource.generator; +// +// ServerLevelLightManager lightEngine = (ServerLevelLightManager) serverLevel.getLightEngine(); +// TemplateManager templateManager = serverLevel.getStructureManager(); +// +// +// // generate the terrain (this is thread safe) +// ChunkStatus.EMPTY.generate(serverLevel, chunkGen, templateManager, lightEngine, null, chunkList); +// // override the chunk status, so we can run the next generator stage +// chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); +// chunkGen.createBiomes(serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), chunk); +// ChunkStatus.NOISE.generate(serverLevel, chunkGen, templateManager, lightEngine, null, chunkList); +// ChunkStatus.SURFACE.generate(serverLevel, chunkGen, templateManager, lightEngine, null, chunkList); +// +// +// // get all the biomes in the chunk +// HashSet biomes = new HashSet<>(); +// for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++) +// { +// for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++) +// { +// Biome biome = chunk.getBiomes().getNoiseBiome(x >> 2, serverLevel.getSeaLevel() >> 2, z >> 2); +// +// // Issue #35 +// // For some reason Jungle biomes cause incredible lag +// // the features here must be interacting with each other +// // in unpredictable ways (specifically tree feature generation). +// // When generating Features my CPU usage generally hovers around 30 - 40% +// // when generating Jungles it spikes to 100%. +// if (biome.getBiomeCategory() != Biome.Category.JUNGLE) +// { +// // should probably use the heightmap here instead of seaLevel, +// // but this seems to get the job done well enough +// biomes.add(biome); +// } +// } +// } +// +// boolean allowUnstableFeatures = LodConfig.CLIENT.worldGenerator.allowUnstableFeatureGeneration.get(); +// +// // generate all the features related to this chunk. +// // this may or may not be thread safe +// for (Biome biome : biomes) +// { +// List>>> featuresForState = biome.generationSettings.features(); +// +// for (List>> suppliers : featuresForState) +// { +// for (Supplier> featureSupplier : suppliers) +// { +// ConfiguredFeature configuredFeature = featureSupplier.get(); +// +// if (!allowUnstableFeatures && +// configuredFeaturesToAvoid.containsKey(configuredFeature.hashCode())) +// continue; +// +// +// try +// { +// configuredFeature.place(lodServerLevel, chunkGen, serverLevel.random, chunk.getPos().getWorldPosition()); +// } +// catch (ConcurrentModificationException e) +// { +// // This will happen. I'm not sure what to do about it +// // except pray that it doesn't affect the normal world generation +// // in any harmful way. +// // Update: this can cause crashes and high CPU usage. +// +// // Issue #35 +// // I tried cloning the config for each feature, but that +// // path was blocked since I can't clone lambda methods. +// // I tried using a deep cloning library and discovered +// // the problem there. +// // ( https://github.com/kostaskougios/cloning +// // and +// // https://github.com/EsotericSoftware/kryo ) +// +// if (!allowUnstableFeatures) +// configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); +//// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); +// } +// catch (UnsupportedOperationException e) +// { +// // This will happen when the LodServerLevel +// // isn't able to return something that a feature +// // generator needs +// +// if (!allowUnstableFeatures) +// configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); +//// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); +// } +// catch (Exception e) +// { +// // I'm not sure what happened, print to the log +// +// e.printStackTrace(); +// +// if (!allowUnstableFeatures) +// configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); +//// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); +// } +// } +// } +// } +// +// // generate a Lod like normal +// lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(DistanceGenerationMode.FEATURES)); +// } /** @@ -574,92 +509,13 @@ public class LodGenWorker implements IWorker */ private void generateWithServer() { - lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES)), new LodBuilderConfig(DistanceGenerationMode.SERVER)); + lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(serverLevel.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FEATURES)), new LodBuilderConfig(DistanceGenerationMode.FEATURES)); } - - //================// - // Unused methods // - //================// - - // Sadly I wasn't able to get these to work, - // they are here for documentation purposes - - @SuppressWarnings({ "rawtypes", "unchecked", "unused" }) - private DecoratedFeatureConfig cloneDecoratedFeatureConfig(DecoratedFeatureConfig config) - { - IPlacementConfig placementConfig; - - Class oldConfigClass = config.decorator.config().getClass(); - - if (oldConfigClass == FeatureSpreadConfig.class) - { - FeatureSpreadConfig oldPlacementConfig = (FeatureSpreadConfig) config.decorator.config(); - FeatureSpread oldSpread = oldPlacementConfig.count(); - - placementConfig = new FeatureSpreadConfig(oldSpread); - } - else if (oldConfigClass == DecoratedPlacementConfig.class) - { - DecoratedPlacementConfig oldPlacementConfig = (DecoratedPlacementConfig) config.decorator.config(); - placementConfig = new DecoratedPlacementConfig(oldPlacementConfig.inner(), oldPlacementConfig.outer()); - } - else if (oldConfigClass == NoiseDependant.class) - { - NoiseDependant oldPlacementConfig = (NoiseDependant) config.decorator.config(); - placementConfig = new NoiseDependant(oldPlacementConfig.noiseLevel, oldPlacementConfig.belowNoise, oldPlacementConfig.aboveNoise); - } - else - { -// ClientProxy.LOGGER.debug("unknown decorated placement config: \"" + config.decorator.config().getClass() + "\""); - return config; - } - - - ConfiguredPlacement newPlacement = new ConfiguredPlacement(config.decorator.decorator, placementConfig); - return new DecoratedFeatureConfig(config.feature, newPlacement); - } - - - @SuppressWarnings("unused") - private BlockClusterFeatureConfig cloneBlockClusterFeatureConfig(BlockClusterFeatureConfig config) - { - WeightedBlockStateProvider provider = new WeightedBlockStateProvider(); - provider.weightedList.entries.addAll(((WeightedBlockStateProvider) config.stateProvider).weightedList.entries); - - HashSet whitelist = new HashSet<>(config.whitelist); - - HashSet blacklist = new HashSet<>(config.blacklist); - - - BlockClusterFeatureConfig.Builder builder = new BlockClusterFeatureConfig.Builder(provider, config.blockPlacer); - builder.whitelist(whitelist); - builder.blacklist(blacklist); - builder.xspread(config.xspread); - builder.yspread(config.yspread); - builder.zspread(config.zspread); - if (config.canReplace) - { - builder.canReplace(); - } - if (config.needWater) - { - builder.needWater(); - } - if (config.project) - { - builder.noProjection(); - } - builder.tries(config.tries); - - - return builder.build(); - } - } @@ -687,7 +543,7 @@ public class LodGenWorker implements IWorker /* * performance/generation tests related to - * serverWorld.getChunk(x, z, ChunkStatus. *** ) + * ServerLevel.getChunk(x, z, ChunkStatus. *** ) true/false is whether they generated blocks or not the time is how long it took to generate diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodServerWorld.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodServerLevel.java.DIS similarity index 80% rename from src/main/java/com/seibel/lod/builders/worldGeneration/LodServerWorld.java rename to src/main/java/com/seibel/lod/builders/worldGeneration/LodServerLevel.java.DIS index 1229a853c..e73aefbbe 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodServerWorld.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodServerLevel.java.DIS @@ -20,47 +20,23 @@ package com.seibel.lod.builders.worldGeneration; import java.util.HashMap; -import java.util.List; import java.util.Random; -import java.util.function.Predicate; import java.util.stream.Stream; import com.seibel.lod.util.LodUtil; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.particles.IParticleData; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.SectionPos; -import net.minecraft.util.registry.DynamicRegistries; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.DimensionType; -import net.minecraft.world.EmptyTickList; -import net.minecraft.world.ISeedReader; -import net.minecraft.world.ITickList; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.BiomeManager; -import net.minecraft.world.border.WorldBorder; -import net.minecraft.world.chunk.AbstractChunkProvider; -import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.gen.Heightmap; -import net.minecraft.world.gen.Heightmap.Type; -import net.minecraft.world.gen.feature.structure.Structure; -import net.minecraft.world.gen.feature.structure.StructureStart; -import net.minecraft.world.lighting.WorldLightManager; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.storage.IWorldInfo; - +import net.minecraft.world.level.EmptyTickList; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.structure.StructureStart; +import net.minecraft.world.level.material.FluidState; /** * This is a fake ServerWorld used when generating features. @@ -70,7 +46,7 @@ import net.minecraft.world.storage.IWorldInfo; * @author James Seibel * @version 7-26-2021 */ -public class LodServerWorld implements ISeedReader +public class LodServerLevel implements Level { public HashMap heightmaps = new HashMap<>(); @@ -79,7 +55,7 @@ public class LodServerWorld implements ISeedReader public final ServerWorld serverWorld; - public LodServerWorld(ServerWorld newServerWorld, IChunk newChunk) + public LodServerLevel(ServerWorld newServerWorld, IChunk newChunk) { chunk = newChunk; serverWorld = newServerWorld; diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java index 736aea480..9a956b410 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodWorldGenerator.java @@ -36,9 +36,9 @@ import com.seibel.lod.util.LevelPosUtil; import com.seibel.lod.util.LodThreadFactory; import com.seibel.lod.util.LodUtil; import com.seibel.lod.wrappers.MinecraftWrapper; +import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.server.ServerWorld; +import net.minecraft.server.level.ServerLevel; import net.minecraftforge.common.WorldWorkerManager; /** @@ -72,7 +72,7 @@ public class LodWorldGenerator */ public final AtomicInteger numberOfChunksWaitingToGenerate = new AtomicInteger(0); - public final Set positionsWaitingToBeGenerated = new HashSet<>(); + public final Set positionsWaitingToBeGenerated = new HashSet<>(); /** * Singleton copy of this object @@ -115,7 +115,7 @@ public class LodWorldGenerator // fill in positionsWaitingToBeGenerated // //=======================================// - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); + ServerLevel serverWorld = LodUtil.getServerLevelFromDimension(lodDim.dimension); PosToGenerateContainer posToGenerate = lodDim.getPosToGenerate( maxChunkGenRequests, @@ -142,7 +142,7 @@ public class LodWorldGenerator posZ = posToGenerate.getNthPosZ(nearIndex, true); nearIndex++; - ChunkPos chunkPos = new ChunkPos(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ)); + ChunkPosWrapper chunkPos = new ChunkPosWrapper(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ)); // prevent generating the same chunk multiple times if (positionsWaitingToBeGenerated.contains(chunkPos)) @@ -167,7 +167,7 @@ public class LodWorldGenerator posZ = posToGenerate.getNthPosZ(farIndex, false); farIndex++; - ChunkPos chunkPos = new ChunkPos(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ)); + ChunkPosWrapper chunkPos = new ChunkPosWrapper(LevelPosUtil.getChunkPos(detailLevel, posX), LevelPosUtil.getChunkPos(detailLevel, posZ)); // don't add more to the generation queue then allowed if (numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests) diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 90c932033..1294af5fd 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -157,6 +157,7 @@ public class ClientProxy } /** used in a development environment to change settings on the fly */ + @SuppressWarnings("unused") private void applyConfigOverrides() { // remind the developer(s) that the config override is active @@ -316,13 +317,12 @@ public class ClientProxy private void playerMoveEvent(LodDimension lodDim) { // make sure the dimension is centered - RegionPos playerRegionPos = new RegionPos(mc.getPlayer().blockPosition()); + RegionPos playerRegionPos = new RegionPos(mc.getPlayerBlockPos()); RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterRegionPosX(), playerRegionPos.z - lodDim.getCenterRegionPosZ()); if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0) { lodWorld.saveAllDimensions(); lodDim.move(worldRegionOffset); - //LOGGER.info("offset: " + worldRegionOffset.x + "," + worldRegionOffset.z + "\t center: " + lodDim.getCenterX() + "," + lodDim.getCenterZ()); } } diff --git a/src/main/java/com/seibel/lod/util/LodUtil.java b/src/main/java/com/seibel/lod/util/LodUtil.java index 3bc7706de..2ea98e02c 100644 --- a/src/main/java/com/seibel/lod/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/util/LodUtil.java @@ -37,14 +37,13 @@ import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper; import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher.CompiledChunk; import net.minecraft.client.server.IntegratedServer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.dimension.DimensionType; @@ -238,12 +237,12 @@ public class LodUtil * world, if in multiplayer it will return the server name, IP, * and game version. */ - public static String getWorldID(Level world) + public static String getWorldID(LevelAccessor levelAccessor) { if (mc.hasSinglePlayerServer()) { // chop off the dimension ID as it is not needed/wanted - String dimId = getDimensionIDFromWorld(world); + String dimId = getDimensionIDFromWorld(levelAccessor); // get the world name int saveIndex = dimId.indexOf("saves") + 1 + "saves".length(); @@ -266,26 +265,26 @@ public class LodUtil * This can be used to determine where to save files for a given * dimension. */ - public static String getDimensionIDFromWorld(Level world) + public static String getDimensionIDFromWorld(LevelAccessor levelAccessor) { if (mc.hasSinglePlayerServer()) { // this will return the world save location // and the dimension folder - ServerLevel ServerLevel = LodUtil.getServerLevelFromDimension(world.dimensionType()); + ServerLevel ServerLevel = LodUtil.getServerLevelFromDimension(levelAccessor.dimensionType()); if (ServerLevel == null) - throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerLevel for the dimension " + world.dimensionType().effectsLocation().getPath()); + throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerLevel for the dimension " + levelAccessor.dimensionType().effectsLocation().getPath()); ServerChunkCache provider = ServerLevel.getChunkSource(); if (provider == null) - throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerChunkProvider for the dimension " + world.dimensionType().effectsLocation().getPath()); + throw new NullPointerException("getDimensionIDFromWorld wasn't able to get the ServerChunkProvider for the dimension " + levelAccessor.dimensionType().effectsLocation().getPath()); return provider.getDataStorage().dataFolder.toString(); } else { - return getServerId() + File.separatorChar + "dim_" + world.dimensionType().effectsLocation().getPath() + File.separatorChar; + return getServerId() + File.separatorChar + "dim_" + levelAccessor.dimensionType().effectsLocation().getPath() + File.separatorChar; } } @@ -459,13 +458,12 @@ public class LodUtil // go through every RenderInfo to get the compiled chunks LevelRenderer renderer = mc.getLevelRenderer(); - for (LevelRenderer.LocalRenderInformationContainer worldRenderer$LocalRenderInformationContainer : renderer.renderChunks) + for (LevelRenderer.RenderChunkInfo chunkInfo : renderer.renderChunks) { - CompiledChunk compiledChunk = worldRenderer$LocalRenderInformationContainer.chunk.getCompiledChunk(); - if (!compiledChunk.hasNoRenderableLayers()) + if (!chunkInfo.chunk.getCompiledChunk().hasNoRenderableLayers()) { // add the ChunkPos for every rendered chunk - BlockPos bpos = worldRenderer$LocalRenderInformationContainer.chunk.getOrigin(); + BlockPos bpos = chunkInfo.chunk.getOrigin(); loadedPos.add(new ChunkPos(bpos)); } diff --git a/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java index 317bc5710..b465f9361 100644 --- a/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java @@ -1,20 +1,14 @@ package com.seibel.lod.wrappers.World; -import com.seibel.lod.util.ColorUtil; -import com.seibel.lod.util.LodUtil; -import com.seibel.lod.wrappers.Block.BlockColorWrapper; -import com.seibel.lod.wrappers.Block.BlockPosWrapper; -import net.minecraft.block.Blocks; -import net.minecraft.block.material.MaterialColor; -import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.BiomeColors; - -import java.awt.*; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import com.seibel.lod.util.LodUtil; + +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.material.MaterialColor; +import net.minecraftforge.client.event.RenderTooltipEvent.Color; //This class wraps the minecraft BlockPos.Mutable (and BlockPos) class public class BiomeWrapper @@ -53,16 +47,16 @@ public class BiomeWrapper { case NETHER: - colorInt = Blocks.NETHERRACK.defaultBlockState().materialColor.col; + colorInt = Blocks.NETHERRACK.defaultBlockState().getMaterial().getColor().col; break; case THEEND: - colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col; + colorInt = Blocks.END_STONE.defaultBlockState().getMaterial().getColor().col; break; case BEACH: case DESERT: - colorInt = Blocks.SAND.defaultBlockState().materialColor.col; + colorInt = Blocks.SAND.defaultBlockState().getMaterial().getColor().col; break; case EXTREME_HILLS: diff --git a/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java index 99a57359a..a599cf130 100644 --- a/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java @@ -1,23 +1,24 @@ package com.seibel.lod.wrappers.World; -import com.seibel.lod.wrappers.Block.BlockPosWrapper; -import net.minecraft.world.IWorld; - import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import com.seibel.lod.wrappers.Block.BlockPosWrapper; + +import net.minecraft.world.level.Level; + public class WorldWrapper { - private static final ConcurrentMap worldWrapperMap = new ConcurrentHashMap<>(); - private IWorld world; + private static final ConcurrentMap worldWrapperMap = new ConcurrentHashMap<>(); + private Level world; - public WorldWrapper(IWorld world) + public WorldWrapper(Level world) { this.world = world; } - public static WorldWrapper getWorldWrapper(IWorld world) + public static WorldWrapper getWorldWrapper(Level world) { //first we check if the biome has already been wrapped if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null) @@ -57,7 +58,7 @@ public class WorldWrapper return BiomeWrapper.getBiomeWrapper(world.getBiome(blockPos.getBlockPos())); } - public IWorld getWorld() + public Level getWorld() { return world; } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 35ca8c96a..32a31049f 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -61,6 +61,16 @@ public net.minecraft.client.renderer.GameRenderer m_109141_(Lnet/minecraft/clien # pre-render setup public net.minecraft.client.renderer.LevelRenderer f_109467_ # renderChunks +public net.minecraft.client.renderer.LevelRenderer$RenderChunkInfo +public net.minecraft.client.renderer.LevelRenderer$RenderChunkInfo f_109839_ # chunk + +# lighting +public net.minecraft.client.renderer.LightTexture f_109871_ # lightPixels +public net.minecraft.world.level.lighting.LevelLightEngine f_75802_ # blockEngine +public net.minecraft.world.level.lighting.LevelLightEngine f_75803_ # skyEngine + +# world generation +public net.minecraft.world.level.levelgen.Heightmap m_64245_(III)V # setHeight