porting - test LodWorldGenerator

This commit is contained in:
James Seibel
2021-10-30 13:22:54 -05:00
parent 71ab3196ea
commit bd569dad2f
9 changed files with 282 additions and 449 deletions
@@ -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())
{
@@ -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<IChunk> chunkList = new LinkedList<>();
ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY);
List<ChunkAccess> 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<IChunk> 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
* <p>
* Causes concurrentModification Exceptions,
* which could cause instability or world generation bugs
*/
private void generateUsingFeatures()
{
List<IChunk> 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<Biome> 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<List<Supplier<ConfiguredFeature<?, ?>>>> featuresForState = biome.generationSettings.features();
for (List<Supplier<ConfiguredFeature<?, ?>>> suppliers : featuresForState)
{
for (Supplier<ConfiguredFeature<?, ?>> 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<ChunkAccess> 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
// * <p>
// * Causes concurrentModification Exceptions,
// * which could cause instability or world generation bugs
// */
// private void generateUsingFeatures()
// {
// List<ChunkAccess> 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<Biome> 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<List<Supplier<ConfiguredFeature<?, ?>>>> featuresForState = biome.generationSettings.features();
//
// for (List<Supplier<ConfiguredFeature<?, ?>>> suppliers : featuresForState)
// {
// for (Supplier<ConfiguredFeature<?, ?>> 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<Block> whitelist = new HashSet<>(config.whitelist);
HashSet<BlockState> 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
@@ -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<Heightmap.Type, Heightmap> 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;
@@ -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<ChunkPos> positionsWaitingToBeGenerated = new HashSet<>();
public final Set<ChunkPosWrapper> 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)
@@ -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());
}
}
+11 -13
View File
@@ -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));
}
@@ -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:
@@ -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<IWorld, WorldWrapper> worldWrapperMap = new ConcurrentHashMap<>();
private IWorld world;
private static final ConcurrentMap<Level, WorldWrapper> 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;
}
@@ -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