mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-02-09 20:05:01 +01:00
Increase layered ore shape variation (#6158)
This commit is contained in:
parent
a41053b896
commit
c92bbdda2d
1 changed files with 112 additions and 64 deletions
|
@ -1,6 +1,7 @@
|
||||||
package com.simibubi.create.infrastructure.worldgen;
|
package com.simibubi.create.infrastructure.worldgen;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@ -20,17 +21,24 @@ import net.minecraft.world.level.levelgen.feature.Feature;
|
||||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration.TargetBlockState;
|
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration.TargetBlockState;
|
||||||
|
import net.minecraft.world.level.levelgen.synth.SimplexNoise;
|
||||||
|
|
||||||
public class LayeredOreFeature extends Feature<LayeredOreConfiguration> {
|
public class LayeredOreFeature extends Feature<LayeredOreConfiguration> {
|
||||||
public LayeredOreFeature() {
|
public LayeredOreFeature() {
|
||||||
super(LayeredOreConfiguration.CODEC);
|
super(LayeredOreConfiguration.CODEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final float MAX_LAYER_DISPLACEMENT = 1.75f;
|
||||||
|
private static final float LAYER_NOISE_FREQUENCY = 0.125f;
|
||||||
|
|
||||||
|
private static final float MAX_RADIAL_THRESHOLD_REDUCTION = 0.25f;
|
||||||
|
private static final float RADIAL_NOISE_FREQUENCY = 0.125f;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean place(FeaturePlaceContext<LayeredOreConfiguration> pContext) {
|
public boolean place(FeaturePlaceContext<LayeredOreConfiguration> pContext) {
|
||||||
RandomSource random = pContext.random();
|
RandomSource random = pContext.random();
|
||||||
BlockPos blockpos = pContext.origin();
|
BlockPos origin = pContext.origin();
|
||||||
WorldGenLevel worldgenlevel = pContext.level();
|
WorldGenLevel worldGenLevel = pContext.level();
|
||||||
LayeredOreConfiguration config = pContext.config();
|
LayeredOreConfiguration config = pContext.config();
|
||||||
List<LayerPattern> patternPool = config.layerPatterns;
|
List<LayerPattern> patternPool = config.layerPatterns;
|
||||||
|
|
||||||
|
@ -40,89 +48,120 @@ public class LayeredOreFeature extends Feature<LayeredOreConfiguration> {
|
||||||
LayerPattern layerPattern = patternPool.get(random.nextInt(patternPool.size()));
|
LayerPattern layerPattern = patternPool.get(random.nextInt(patternPool.size()));
|
||||||
|
|
||||||
int placedAmount = 0;
|
int placedAmount = 0;
|
||||||
int size = config.size;
|
int size = config.size + 1;
|
||||||
int radius = Mth.ceil(config.size / 2f);
|
float radius = config.size * 0.5f;
|
||||||
int x0 = blockpos.getX() - radius;
|
int radiusBound = Mth.ceil(radius) - 1;
|
||||||
int y0 = blockpos.getY() - radius;
|
int x0 = origin.getX();
|
||||||
int z0 = blockpos.getZ() - radius;
|
int y0 = origin.getY();
|
||||||
int width = size + 1;
|
int z0 = origin.getZ();
|
||||||
int length = size + 1;
|
|
||||||
int height = size + 1;
|
|
||||||
|
|
||||||
if (blockpos.getY() >= worldgenlevel.getHeight(Heightmap.Types.OCEAN_FLOOR_WG, blockpos.getX(),
|
if (origin.getY() >= worldGenLevel.getHeight(Heightmap.Types.OCEAN_FLOOR_WG, origin.getX(), origin.getZ()))
|
||||||
blockpos.getZ()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
List<LayerPattern.Layer> resolvedLayers = new ArrayList<>();
|
List<TemporaryLayerEntry> tempLayers = new ArrayList<>();
|
||||||
List<Float> layerDiameterOffsets = new ArrayList<>();
|
float layerSizeTotal = 0.0f;
|
||||||
|
LayerPattern.Layer current = null;
|
||||||
|
while (layerSizeTotal < size) {
|
||||||
|
Layer next = layerPattern.rollNext(current, random);
|
||||||
|
float layerSize = Mth.randomBetween(random, next.minSize, next.maxSize);
|
||||||
|
tempLayers.add(new TemporaryLayerEntry(next, layerSize));
|
||||||
|
layerSizeTotal += layerSize;
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ResolvedLayerEntry> resolvedLayers = new ArrayList<>(tempLayers.size());
|
||||||
|
float cumulativeLayerSize = -(layerSizeTotal - size) * random.nextFloat();
|
||||||
|
for (TemporaryLayerEntry tempLayerEntry : tempLayers) {
|
||||||
|
float rampStartValue = resolvedLayers.size() == 0 ?
|
||||||
|
Float.NEGATIVE_INFINITY :
|
||||||
|
cumulativeLayerSize * (2.0f / size) - 1.0f;
|
||||||
|
cumulativeLayerSize += tempLayerEntry.size();
|
||||||
|
if (cumulativeLayerSize < 0)
|
||||||
|
continue;
|
||||||
|
float radialThresholdMultiplier = Mth.randomBetween(random, 0.5f, 1.0f);
|
||||||
|
resolvedLayers.add(new ResolvedLayerEntry(tempLayerEntry.layer, radialThresholdMultiplier, rampStartValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose stacking direction
|
||||||
|
float gy = Mth.randomBetween(random, -1.0f, 1.0f);
|
||||||
|
gy = (float) Math.cbrt(gy); // Make layer alignment tend towards horizontal more than vertical
|
||||||
|
float xzRescale = Mth.sqrt(1.0f - gy * gy);
|
||||||
|
float theta = random.nextFloat() * Mth.TWO_PI;
|
||||||
|
float gx = Mth.cos(theta) * xzRescale;
|
||||||
|
float gz = Mth.sin(theta) * xzRescale;
|
||||||
|
|
||||||
|
SimplexNoise layerDisplacementNoise = new SimplexNoise(random);
|
||||||
|
SimplexNoise radiusNoise = new SimplexNoise(random);
|
||||||
|
|
||||||
MutableBlockPos mutablePos = new MutableBlockPos();
|
MutableBlockPos mutablePos = new MutableBlockPos();
|
||||||
BulkSectionAccess bulksectionaccess = new BulkSectionAccess(worldgenlevel);
|
BulkSectionAccess bulkSectionAccess = new BulkSectionAccess(worldGenLevel);
|
||||||
int layerCoordinate = random.nextInt(4);
|
|
||||||
int slantyCoordinate = random.nextInt(3);
|
|
||||||
float slope = random.nextFloat() * .75f;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
for (int x = 0; x < width; x++) {
|
for (int dzBlock = -radiusBound; dzBlock <= radiusBound; dzBlock++) {
|
||||||
float dx = x * 2f / width - 1;
|
float dz = dzBlock * (1.0f / radius);
|
||||||
if (dx * dx > 1)
|
if (dz * dz > 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int dxBlock = -radiusBound; dxBlock <= radiusBound; dxBlock++) {
|
||||||
float dy = y * 2f / height - 1;
|
float dx = dxBlock * (1.0f / radius);
|
||||||
if (dx * dx + dy * dy > 1)
|
if (dz * dz + dx * dx > 1)
|
||||||
continue;
|
|
||||||
if (worldgenlevel.isOutsideBuildHeight(y0 + y))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int z = 0; z < length; z++) {
|
for (int dyBlock = -radiusBound; dyBlock <= radiusBound; dyBlock++) {
|
||||||
float dz = z * 2f / height - 1;
|
float dy = dyBlock * (1.0f / radius);
|
||||||
|
float distanceSquared = dz * dz + dx * dx + dy * dy;
|
||||||
int layerIndex = layerCoordinate == 0 ? z : layerCoordinate == 1 ? x : y;
|
if (distanceSquared > 1)
|
||||||
if (slantyCoordinate != layerCoordinate)
|
continue;
|
||||||
layerIndex += Mth.floor(slantyCoordinate == 0 ? z : slantyCoordinate == 1 ? x : y) * slope;
|
if (worldGenLevel.isOutsideBuildHeight(y0 + dyBlock))
|
||||||
|
|
||||||
while (layerIndex >= resolvedLayers.size()) {
|
|
||||||
Layer next = layerPattern.rollNext(
|
|
||||||
resolvedLayers.isEmpty() ? null : resolvedLayers.get(resolvedLayers.size() - 1),
|
|
||||||
random);
|
|
||||||
float offset = random.nextFloat() * .5f + .5f;
|
|
||||||
for (int i = 0; i < next.minSize + random.nextInt(1 + next.maxSize - next.minSize); i++) {
|
|
||||||
resolvedLayers.add(next);
|
|
||||||
layerDiameterOffsets.add(offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dx * dx + dy * dy + dz * dz > 1 * layerDiameterOffsets.get(layerIndex))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LayerPattern.Layer layer = resolvedLayers.get(layerIndex);
|
int currentX = x0 + dxBlock;
|
||||||
List<TargetBlockState> state = layer.rollBlock(random);
|
int currentY = y0 + dyBlock;
|
||||||
|
int currentZ = z0 + dzBlock;
|
||||||
|
|
||||||
int currentX = x0 + x;
|
float rampValue = gx * dx + gy * dy + gz * dz;
|
||||||
int currentY = y0 + y;
|
rampValue += layerDisplacementNoise.getValue(
|
||||||
int currentZ = z0 + z;
|
currentX * LAYER_NOISE_FREQUENCY, currentY * LAYER_NOISE_FREQUENCY, currentZ * LAYER_NOISE_FREQUENCY
|
||||||
|
) * (MAX_LAYER_DISPLACEMENT / size);
|
||||||
|
|
||||||
|
int layerIndex = Collections.binarySearch(resolvedLayers, new ResolvedLayerEntry(null, 0, rampValue));
|
||||||
|
if (layerIndex < 0) layerIndex = -2 - layerIndex; // Counter (-insertionIndex - 1) return result, where insertionIndex = layerIndex + 1
|
||||||
|
ResolvedLayerEntry layerEntry = resolvedLayers.get(layerIndex);
|
||||||
|
|
||||||
|
if (distanceSquared > layerEntry.radialThresholdMultiplier)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float thresholdNoiseValue = Mth.map(
|
||||||
|
(float) radiusNoise.getValue(currentX * RADIAL_NOISE_FREQUENCY, currentY * RADIAL_NOISE_FREQUENCY, currentZ * RADIAL_NOISE_FREQUENCY),
|
||||||
|
-1.0f, 1.0f, 1.0f - MAX_RADIAL_THRESHOLD_REDUCTION, 1.0f
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distanceSquared > layerEntry.radialThresholdMultiplier * thresholdNoiseValue)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LayerPattern.Layer layer = layerEntry.layer;
|
||||||
|
List<TargetBlockState> targetBlockStates = layer.rollBlock(random);
|
||||||
|
|
||||||
mutablePos.set(currentX, currentY, currentZ);
|
mutablePos.set(currentX, currentY, currentZ);
|
||||||
if (!worldgenlevel.ensureCanWrite(mutablePos))
|
if (!worldGenLevel.ensureCanWrite(mutablePos))
|
||||||
continue;
|
continue;
|
||||||
LevelChunkSection levelchunksection = bulksectionaccess.getSection(mutablePos);
|
LevelChunkSection levelChunkSection = bulkSectionAccess.getSection(mutablePos);
|
||||||
if (levelchunksection == null)
|
if (levelChunkSection == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int i3 = SectionPos.sectionRelative(currentX);
|
int localX = SectionPos.sectionRelative(currentX);
|
||||||
int j3 = SectionPos.sectionRelative(currentY);
|
int localY = SectionPos.sectionRelative(currentY);
|
||||||
int k3 = SectionPos.sectionRelative(currentZ);
|
int localZ = SectionPos.sectionRelative(currentZ);
|
||||||
BlockState blockstate = levelchunksection.getBlockState(i3, j3, k3);
|
BlockState blockState = levelChunkSection.getBlockState(localX, localY, localZ);
|
||||||
|
|
||||||
for (OreConfiguration.TargetBlockState oreconfiguration$targetblockstate : state) {
|
for (OreConfiguration.TargetBlockState targetBlockState : targetBlockStates) {
|
||||||
if (!canPlaceOre(blockstate, bulksectionaccess::getBlockState, random, config,
|
if (!canPlaceOre(blockState, bulkSectionAccess::getBlockState, random, config,
|
||||||
oreconfiguration$targetblockstate, mutablePos))
|
targetBlockState, mutablePos))
|
||||||
continue;
|
continue;
|
||||||
if (oreconfiguration$targetblockstate.state.isAir())
|
if (targetBlockState.state.isAir())
|
||||||
continue;
|
continue;
|
||||||
levelchunksection.setBlockState(i3, j3, k3, oreconfiguration$targetblockstate.state, false);
|
levelChunkSection.setBlockState(localX, localY, localZ, targetBlockState.state, false);
|
||||||
++placedAmount;
|
++placedAmount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +172,7 @@ public class LayeredOreFeature extends Feature<LayeredOreConfiguration> {
|
||||||
|
|
||||||
} catch (Throwable throwable1) {
|
} catch (Throwable throwable1) {
|
||||||
try {
|
try {
|
||||||
bulksectionaccess.close();
|
bulkSectionAccess.close();
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throwable1.addSuppressed(throwable);
|
throwable1.addSuppressed(throwable);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +180,7 @@ public class LayeredOreFeature extends Feature<LayeredOreConfiguration> {
|
||||||
throw throwable1;
|
throw throwable1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bulksectionaccess.close();
|
bulkSectionAccess.close();
|
||||||
return placedAmount > 0;
|
return placedAmount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,4 +198,13 @@ public class LayeredOreFeature extends Feature<LayeredOreConfiguration> {
|
||||||
protected boolean shouldSkipAirCheck(RandomSource pRandom, float pChance) {
|
protected boolean shouldSkipAirCheck(RandomSource pRandom, float pChance) {
|
||||||
return pChance <= 0 ? true : pChance >= 1 ? false : pRandom.nextFloat() >= pChance;
|
return pChance <= 0 ? true : pChance >= 1 ? false : pRandom.nextFloat() >= pChance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record TemporaryLayerEntry(Layer layer, float size) { }
|
||||||
|
|
||||||
|
private record ResolvedLayerEntry(Layer layer, float radialThresholdMultiplier, float rampStartValue) implements Comparable<ResolvedLayerEntry> {
|
||||||
|
@Override
|
||||||
|
public int compareTo(LayeredOreFeature.ResolvedLayerEntry b) {
|
||||||
|
return Float.compare(rampStartValue, b.rampStartValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue