From a533ffc4c9f20901732418224f172d78931249ec Mon Sep 17 00:00:00 2001 From: coolGi2007 Date: Sun, 12 Dec 2021 01:34:24 +0000 Subject: [PATCH] Updated core --- .../lod/common/wrappers/WrapperFactory.java | 4 +- .../WorldGeneratorWrapper.java | 323 +++--------------- core | 2 +- 3 files changed, 52 insertions(+), 277 deletions(-) diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java index 4383458a8..7050be8a4 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java @@ -80,12 +80,12 @@ public class WrapperFactory implements IWrapperFactory return new ChunkPosWrapper(blockPos); } - - @Override public AbstractWorldGeneratorWrapper createWorldGenerator(LodBuilder newLodBuilder, LodDimension newLodDimension, IWorldWrapper worldWrapper) { return new WorldGeneratorWrapper(newLodBuilder, newLodDimension, worldWrapper); } + @Override + public boolean isWorldGeneratorSingleThreaded() {return true;} } diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGeneratorWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGeneratorWrapper.java index 66bf540af..46f18d3fb 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGeneratorWrapper.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGeneratorWrapper.java @@ -1,41 +1,24 @@ package com.seibel.lod.common.wrappers.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 java.util.concurrent.ExecutionException; import com.seibel.lod.core.builders.lodBuilding.LodBuilder; import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig; import com.seibel.lod.core.enums.config.DistanceGenerationMode; import com.seibel.lod.core.objects.lod.LodDimension; -import com.seibel.lod.core.util.LodUtil; -import com.seibel.lod.core.util.SingletonHandler; +//import com.seibel.lod.core.util.SingletonHandler; import com.seibel.lod.core.wrapperInterfaces.chunk.AbstractChunkPosWrapper; -import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; +//import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper; import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractWorldGeneratorWrapper; -import com.seibel.lod.common.wrappers.WrapperUtil; -import com.seibel.lod.common.wrappers.chunk.ChunkPosWrapper; import com.seibel.lod.common.wrappers.chunk.ChunkWrapper; import com.seibel.lod.common.wrappers.world.WorldWrapper; -import net.minecraft.core.Registry; +import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.*; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; -import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; -import net.minecraft.world.level.levelgen.feature.SnowAndFreezeFeature; -import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; /** * @author James Seibel @@ -43,16 +26,16 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureMana */ public class WorldGeneratorWrapper extends AbstractWorldGeneratorWrapper { - private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); + //private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); /** * If a configured feature fails for whatever reason, * add it to this list. This will hopefully remove any * features that could cause issues down the line. */ - private static final ConcurrentHashMap> FEATURES_TO_AVOID = new ConcurrentHashMap<>(); + //private static final ConcurrentHashMap> FEATURES_TO_AVOID = new ConcurrentHashMap<>(); - private static ExecutorService Executor = Executors.newSingleThreadExecutor(); + //private static ExecutorService Executor = Executors.newSingleThreadExecutor(); public final ServerLevel serverWorld; @@ -69,119 +52,11 @@ public class WorldGeneratorWrapper extends AbstractWorldGeneratorWrapper } - - - - - /** takes about 2-5 ms */ @Override public void generateBiomesOnly(AbstractChunkPosWrapper pos, DistanceGenerationMode generationMode) { - List chunkList = new LinkedList<>(); - ProtoChunk chunk = new ProtoChunk(((ChunkPosWrapper) pos).getChunkPos(), UpgradeData.EMPTY, serverWorld); - chunkList.add(chunk); - - ServerChunkCache chunkSource = serverWorld.getChunkSource(); - ChunkGenerator chunkGen = chunkSource.getGenerator(); - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(Executor, serverWorld, chunkGen, serverWorld.getStructureManager(), (ThreadedLevelLightEngine) serverWorld.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); - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - - - - - // generate fake height data for this LOD - int seaLevel = serverWorld.getSeaLevel(); - - boolean simulateHeight = generationMode == DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT; - boolean inTheEnd = false; - - // add fake heightmap data so our LODs aren't at height 0 - Heightmap heightmap = new Heightmap(chunk, WrapperUtil.DEFAULT_HEIGHTMAP); - for (int x = 0; x < LodUtil.CHUNK_WIDTH && !inTheEnd; x++) - { - for (int z = 0; z < LodUtil.CHUNK_WIDTH && !inTheEnd; z++) - { - if (simulateHeight) - { - // these heights are of course aren't super accurate, - // they are just to simulate height data where there isn't any - switch (chunk.getBiomes().getNoiseBiome(x >> 2, seaLevel >> 2, z >> 2).getBiomeCategory()) - { - case NETHER: - heightmap.setHeight(x, z, serverWorld.getHeight() / 2); - break; - - case EXTREME_HILLS: - heightmap.setHeight(x, z, seaLevel + 30); - break; - case MESA: - case JUNGLE: - heightmap.setHeight(x, z, seaLevel + 20); - break; - case BEACH: - heightmap.setHeight(x, z, seaLevel + 5); - break; - case NONE: - heightmap.setHeight(x, z, 0); - break; - - case OCEAN: - case RIVER: - heightmap.setHeight(x, z, seaLevel); - break; - - case THEEND: - inTheEnd = true; - break; - - // DESERT - // FOREST - // ICY - // MUSHROOM - // SAVANNA - // SWAMP - // TAIGA - // PLAINS - default: - heightmap.setHeight(x, z, seaLevel + 10); - break; - }// heightmap switch - } - else - { - // we aren't simulating height - // always use sea level - heightmap.setHeight(x, z, seaLevel); - } - }// z - }// x - - chunk.setHeightmap(WrapperUtil.DEFAULT_HEIGHTMAP, heightmap.getRawData()); - - - if (!inTheEnd) - { - lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(true, true, false)); - } - else - { - // if we are in the end, don't generate any chunks. - // Since we don't know where the islands are, everything - // generates the same, and it looks awful. - //TODO it appears that 'if' can be collapsed, but comment says that it should not be a case - lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(true, true, false)); - } - - -// long startTime = System.currentTimeMillis(); -// long endTime = System.currentTimeMillis(); -// System.out.println(endTime - startTime); + generate(pos.getX(), pos.getZ(), generationMode); } @@ -189,39 +64,7 @@ public class WorldGeneratorWrapper extends AbstractWorldGeneratorWrapper @Override public void generateSurface(AbstractChunkPosWrapper pos) { - List chunkList = new LinkedList<>(); - ProtoChunk chunk = new ProtoChunk(((ChunkPosWrapper) pos).getChunkPos(), UpgradeData.EMPTY, serverWorld); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkCache chunkSource = serverWorld.getChunkSource(); - ThreadedLevelLightEngine lightEngine = (ThreadedLevelLightEngine) serverWorld.getLightEngine(); - StructureManager templateManager = serverWorld.getStructureManager(); - ChunkGenerator chunkGen = chunkSource.getGenerator(); - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(Executor, 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(Executor, serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - // TODO: Find why this doesn't work (seems like the "Executor" is doing this) - ChunkStatus.SURFACE.generate(Executor, serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - - // this feature has been proven to be thread safe, - // so we will add it - - // TODO: Find why this doesn't work -// FeaturePlaceContext featurePlaceContext = new FeaturePlaceContext<>(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null); -// SnowAndFreezeFeature snowFeature = new SnowAndFreezeFeature(NoneFeatureConfiguration.CODEC); -// snowFeature.place(featurePlaceContext); - - - 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());*/ + generate(pos.getX(), pos.getZ(), DistanceGenerationMode.SURFACE); } @@ -234,112 +77,7 @@ public class WorldGeneratorWrapper extends AbstractWorldGeneratorWrapper @Override public void generateFeatures(AbstractChunkPosWrapper pos) { - List chunkList = new LinkedList<>(); - ProtoChunk chunk = new ProtoChunk(((ChunkPosWrapper) pos).getChunkPos(), UpgradeData.EMPTY, serverWorld); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkCache chunkSource = serverWorld.getChunkSource(); - ThreadedLevelLightEngine lightEngine = (ThreadedLevelLightEngine) serverWorld.getLightEngine(); - StructureManager templateManager = serverWorld.getStructureManager(); - ChunkGenerator chunkGen = chunkSource.getGenerator(); - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(Executor, 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(Executor, serverWorld, chunkGen, templateManager, lightEngine, null, chunkList); - // TODO[FABRIC]: Find whay this dosnt work - ChunkStatus.SURFACE.generate(Executor, 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.BiomeCategory.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 = CONFIG.client().worldGenerator().getAllowUnstableFeatureGeneration(); - - // 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 && - FEATURES_TO_AVOID.containsKey(configuredFeature.hashCode())) - continue; - - - try - { - configuredFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition()); - } - catch (ConcurrentModificationException | UnsupportedOperationException 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) - FEATURES_TO_AVOID.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - // This will happen when the LodServerWorld - // isn't able to return something that a feature - // generator needs - catch (Exception e) - { - // I'm not sure what happened, print to the log - - e.printStackTrace(); - - if (!allowUnstableFeatures) - FEATURES_TO_AVOID.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - } - } - } - - // generate a Lod like normal - lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(DistanceGenerationMode.FEATURES)); + generate(pos.getX(), pos.getZ(), DistanceGenerationMode.FEATURES); } @@ -357,7 +95,44 @@ public class WorldGeneratorWrapper extends AbstractWorldGeneratorWrapper @Override public void generateFull(AbstractChunkPosWrapper pos) { - lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(serverWorld.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FEATURES)), new LodBuilderConfig(DistanceGenerationMode.FULL)); + generate(pos.getX(), pos.getZ(), DistanceGenerationMode.FULL); + } + + private void generate(int chunkX, int chunkZ, DistanceGenerationMode generationMode) { + + long t = System.nanoTime(); + + ChunkStatus targetStatus; + switch (generationMode) { + case NONE: + return; + case BIOME_ONLY: + targetStatus = ChunkStatus.BIOMES; + break; + case BIOME_ONLY_SIMULATE_HEIGHT: + targetStatus = ChunkStatus.NOISE; + break; + case SURFACE: + targetStatus = ChunkStatus.SURFACE; + break; + case FEATURES: + targetStatus = ChunkStatus.FEATURES; + break; + case FULL: + targetStatus = ChunkStatus.FULL; + break; + default: + return; + } + + ChunkAccess ca = serverWorld.getChunkSource().getChunk(chunkX, chunkZ, targetStatus, true); + if (ca == null) throw new RuntimeException("This should NEVER be null due to bool being true"); + lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(ca), new LodBuilderConfig(generationMode)); + + long duration = System.nanoTime()-t; + + System.out.println("LodChunkGenFull["+chunkX+","+chunkZ+"]: "+(double)(duration)/1000.); + } diff --git a/core b/core index 56b80f00e..aa9e49b3e 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 56b80f00e83a6ef9e5c7917b92eff8878f973e2b +Subproject commit aa9e49b3e7f0a012396301b432daa95a69eefb5b