mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
fix beardification
This commit is contained in:
@@ -38,6 +38,10 @@ public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties {
|
||||
@Default
|
||||
private double beardThreshold = 0.5;
|
||||
|
||||
@Value("fabric.beard.air-threshold")
|
||||
@Default
|
||||
private double airThreshold = -0.5;
|
||||
|
||||
public boolean useVanillaBiomes() {
|
||||
return vanillaBiomes;
|
||||
}
|
||||
@@ -49,4 +53,8 @@ public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties {
|
||||
public double getBeardThreshold() {
|
||||
return beardThreshold;
|
||||
}
|
||||
|
||||
public double getAirThreshold() {
|
||||
return airThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
package com.dfsek.terra.fabric.generation;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.structure.JigsawJunction;
|
||||
import net.minecraft.structure.PoolStructurePiece;
|
||||
import net.minecraft.structure.StructurePiece;
|
||||
import net.minecraft.structure.StructureStart;
|
||||
import net.minecraft.structure.pool.StructurePool.Projection;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.BlockBox;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.gen.StructureAccessor;
|
||||
import net.minecraft.world.gen.StructureTerrainAdaptation;
|
||||
import net.minecraft.world.gen.StructureWeightSampler;
|
||||
import net.minecraft.world.gen.StructureWeightSampler.class_7301;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
|
||||
|
||||
// net.minecraft.world.gen.StructureWeightSampler
|
||||
public class BeardGenerator {
|
||||
private static final float[] STRUCTURE_WEIGHT_TABLE = Util.make(new float[13824], array -> {
|
||||
for(int i = 0; i < 24; ++i) {
|
||||
for(int j = 0; j < 24; ++j) {
|
||||
for(int k = 0; k < 24; ++k) {
|
||||
array[i * 24 * 24 + j * 24 + k] = (float)calculateStructureWeight(j - 12, k - 12, i - 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
private final ObjectListIterator<StructureWeightSampler.class_7301> pieceIterator;
|
||||
private final ObjectListIterator<JigsawJunction> junctionIterator;
|
||||
private final Chunk chunk;
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
|
||||
private final double threshold;
|
||||
|
||||
public BeardGenerator(StructureAccessor structureAccessor, Chunk chunk, double threshold) {
|
||||
this.chunk = chunk;
|
||||
this.threshold = threshold;
|
||||
ChunkPos chunkPos = chunk.getPos();
|
||||
int i = chunkPos.getStartX();
|
||||
int j = chunkPos.getStartZ();
|
||||
ObjectList<JigsawJunction> junctions = new ObjectArrayList<>(32);
|
||||
ObjectList<class_7301> pieces = new ObjectArrayList<>(10);
|
||||
int minY = chunk.getBottomY();
|
||||
int maxY = chunk.getTopY();
|
||||
for(StructureStart structureStart : structureAccessor.method_41035(chunkPos,
|
||||
structureType -> structureType.getTerrainAdaptation() !=
|
||||
StructureTerrainAdaptation.NONE)) {
|
||||
StructureTerrainAdaptation structureTerrainAdaptation = structureStart.getStructure().getTerrainAdaptation();
|
||||
|
||||
for(StructurePiece structurePiece : structureStart.getChildren()) {
|
||||
if(structurePiece.intersectsChunk(chunkPos, 12)) {
|
||||
if(structurePiece instanceof PoolStructurePiece poolStructurePiece) {
|
||||
Projection projection = poolStructurePiece.getPoolElement().getProjection();
|
||||
if(projection == Projection.RIGID) {
|
||||
pieces.add(
|
||||
new class_7301(
|
||||
poolStructurePiece.getBoundingBox(), structureTerrainAdaptation,
|
||||
poolStructurePiece.getGroundLevelDelta()
|
||||
)
|
||||
);
|
||||
maxY = Math.max(maxY, poolStructurePiece.getCenter().getY());
|
||||
minY = Math.min(minY, poolStructurePiece.getCenter().getY());
|
||||
}
|
||||
|
||||
for(JigsawJunction jigsawJunction : poolStructurePiece.getJunctions()) {
|
||||
int k = jigsawJunction.getSourceX();
|
||||
int l = jigsawJunction.getSourceZ();
|
||||
if(k > i - 12 && l > j - 12 && k < i + 15 + 12 && l < j + 15 + 12) {
|
||||
junctions.add(jigsawJunction);
|
||||
maxY = Math.max(maxY, jigsawJunction.getSourceGroundY());
|
||||
minY = Math.min(minY, jigsawJunction.getSourceGroundY());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pieces.add(new class_7301(structurePiece.getBoundingBox(), structureTerrainAdaptation, 0));
|
||||
maxY = Math.max(maxY, structurePiece.getCenter().getY());
|
||||
minY = Math.min(minY, structurePiece.getCenter().getY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
this.pieceIterator = pieces.iterator();
|
||||
this.junctionIterator = junctions.iterator();
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
private static double getMagnitudeWeight(int x, int y, int z) {
|
||||
double d = MathHelper.magnitude(x, (double) y / 2.0, z);
|
||||
return MathHelper.clampedLerpFromProgress(d, 0.0, 6.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the structure weight from the array from the given position, or 0 if the position is out of bounds.
|
||||
*/
|
||||
private static double getStructureWeight(int x, int y, int z, int i) {
|
||||
int j = x + 12;
|
||||
int k = y + 12;
|
||||
int l = z + 12;
|
||||
if (isInRange(j) && isInRange(k) && isInRange(l)) {
|
||||
double d = (double)i + 0.5;
|
||||
double e = MathHelper.squaredMagnitude(x, d, z);
|
||||
double f = -d * MathHelper.fastInverseSqrt(e / 2.0) / 2.0;
|
||||
return f * (double)STRUCTURE_WEIGHT_TABLE[l * 24 * 24 + j * 24 + k];
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInRange(int i) {
|
||||
return i >= 0 && i < 24;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the structure weight for the given position.
|
||||
* <p>The weight increases as x and z approach {@code (0, 0)}, and positive y values make the weight negative while negative y
|
||||
* values make the weight positive.
|
||||
*/
|
||||
private static double calculateStructureWeight(int x, int y, int z) {
|
||||
double horizontalDistanceSquared = x * x + z * z;
|
||||
double yOffset = y + 0.5;
|
||||
double verticalSquared = yOffset * yOffset;
|
||||
double naturalDistance = Math.pow(Math.E, -(verticalSquared / 16.0 + horizontalDistanceSquared / 16.0));
|
||||
double inverseSquareRootDistance = -yOffset * MathHelper.fastInverseSqrt(verticalSquared / 2.0 + horizontalDistanceSquared / 2.0) /
|
||||
2.0;
|
||||
return inverseSquareRootDistance * naturalDistance;
|
||||
}
|
||||
|
||||
public void generate(ChunkGenerator generator, WorldProperties worldProperties, BiomeProvider biomeProvider) {
|
||||
int xi = chunk.getPos().x << 4;
|
||||
int zi = chunk.getPos().z << 4;
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
int depth = 0;
|
||||
for(int y = maxY; y >= minY; y--) {
|
||||
if(calculateNoise(x + xi, y, z + zi) > threshold) {
|
||||
chunk.setBlockState(new BlockPos(x, y, z), (BlockState) generator
|
||||
.getPalette(x + xi, y, z + zi, worldProperties, biomeProvider)
|
||||
.get(depth, x + xi, y, z + zi, worldProperties.getSeed()), false);
|
||||
depth++;
|
||||
} else {
|
||||
depth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double calculateNoise(int x, int y, int z) {
|
||||
double d;
|
||||
double var10001;
|
||||
for(d = 0.0; this.pieceIterator.hasNext(); d += var10001) {
|
||||
StructureWeightSampler.class_7301 lv = this.pieceIterator.next();
|
||||
BlockBox blockBox = lv.box();
|
||||
int l = lv.groundLevelDelta();
|
||||
int m = Math.max(0, Math.max(blockBox.getMinX() - x, x - blockBox.getMaxX()));
|
||||
int n = Math.max(0, Math.max(blockBox.getMinZ() - z, z - blockBox.getMaxZ()));
|
||||
int o = blockBox.getMinY() + l;
|
||||
int p = y - o;
|
||||
|
||||
int q = switch(lv.terrainAdjustment()) {
|
||||
case NONE -> 0;
|
||||
case BURY, BEARD_THIN -> p;
|
||||
case BEARD_BOX -> Math.max(0, Math.max(o - y, y - blockBox.getMaxY()));
|
||||
};
|
||||
var10001 = switch(lv.terrainAdjustment()) {
|
||||
case NONE -> 0.0;
|
||||
case BURY -> getMagnitudeWeight(m, q, n);
|
||||
case BEARD_THIN, BEARD_BOX -> getStructureWeight(m, q, n, p) * 0.8;
|
||||
};
|
||||
}
|
||||
|
||||
this.pieceIterator.back(Integer.MAX_VALUE);
|
||||
|
||||
while(this.junctionIterator.hasNext()) {
|
||||
JigsawJunction jigsawJunction = this.junctionIterator.next();
|
||||
int r = x - jigsawJunction.getSourceX();
|
||||
int l = y - jigsawJunction.getSourceGroundY();
|
||||
int m = z - jigsawJunction.getSourceZ();
|
||||
d += getStructureWeight(r, l, m, l) * 0.4;
|
||||
}
|
||||
|
||||
this.junctionIterator.back(Integer.MAX_VALUE);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ package com.dfsek.terra.fabric.generation;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.structure.StructureSet;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.random.CheckedRandom;
|
||||
@@ -38,9 +38,12 @@ import net.minecraft.world.biome.source.BiomeAccess;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.gen.GenerationStep.Carver;
|
||||
import net.minecraft.world.gen.StructureAccessor;
|
||||
import net.minecraft.world.gen.StructureWeightSampler;
|
||||
import net.minecraft.world.gen.chunk.Blender;
|
||||
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
|
||||
import net.minecraft.world.gen.chunk.VerticalBlockSample;
|
||||
import net.minecraft.world.gen.densityfunction.DensityFunction.NoisePos;
|
||||
import net.minecraft.world.gen.densityfunction.DensityFunction.UnblendedNoisePos;
|
||||
import net.minecraft.world.gen.noise.NoiseConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -115,6 +118,8 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
|
||||
return settings.value().generationShapeConfig().height();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Chunk> populateNoise(Executor executor, Blender blender, NoiseConfig noiseConfig,
|
||||
StructureAccessor structureAccessor, Chunk chunk) {
|
||||
@@ -125,13 +130,39 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
|
||||
|
||||
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
|
||||
if(compatibilityOptions.isBeard()) {
|
||||
new BeardGenerator(structureAccessor, chunk, compatibilityOptions.getBeardThreshold()).generate(delegate, world,
|
||||
biomeProvider);
|
||||
beard(structureAccessor, chunk, world, biomeProvider, compatibilityOptions);
|
||||
}
|
||||
return chunk;
|
||||
}, executor);
|
||||
}
|
||||
|
||||
private void beard(StructureAccessor structureAccessor, Chunk chunk, WorldProperties world, BiomeProvider biomeProvider,
|
||||
PreLoadCompatibilityOptions compatibilityOptions) {
|
||||
StructureWeightSampler structureWeightSampler = StructureWeightSampler.method_42695(structureAccessor, chunk.getPos());
|
||||
double threshold = compatibilityOptions.getBeardThreshold();
|
||||
double airThreshold = compatibilityOptions.getAirThreshold();
|
||||
int xi = chunk.getPos().x << 4;
|
||||
int zi = chunk.getPos().z << 4;
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
int depth = 0;
|
||||
for(int y = world.getMaxHeight(); y >= world.getMinHeight(); y--) {
|
||||
double noise = structureWeightSampler.sample(new UnblendedNoisePos(x + xi, y, z + zi));
|
||||
if(noise > threshold) {
|
||||
chunk.setBlockState(new BlockPos(x, y, z), (BlockState) delegate
|
||||
.getPalette(x + xi, y, z + zi, world, biomeProvider)
|
||||
.get(depth, x + xi, y, z + zi, world.getSeed()), false);
|
||||
depth++;
|
||||
} else if(noise > 0 && noise < airThreshold) {
|
||||
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.getDefaultState(), false);
|
||||
} else {
|
||||
depth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateFeatures(StructureWorldAccess world, Chunk chunk, StructureAccessor structureAccessor) {
|
||||
super.generateFeatures(world, chunk, structureAccessor);
|
||||
|
||||
Reference in New Issue
Block a user