add beardification support

This commit is contained in:
dfsek
2021-12-31 23:19:21 -07:00
parent 83029989b9
commit 069b0d425a
6 changed files with 197 additions and 12 deletions

View File

@@ -41,7 +41,7 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer {
event.getPack()
.getOrCreateRegistry(ChunkGeneratorProvider.class)
.register(addon.key("NOISE_3D"),
pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(), config.getHorizontalRes(),
pack -> new NoiseChunkGenerator3D(platform, config.getElevationBlend(), config.getHorizontalRes(),
config.getVerticalRes()));
event.getPack()
.applyLoader(SlantLayer.class, SlantLayer::new);

View File

@@ -20,7 +20,6 @@ import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@@ -38,11 +37,9 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
private final int carverHorizontalResolution;
private final int carverVerticalResolution;
private final ConfigPack configPack;
public NoiseChunkGenerator3D(ConfigPack c, Platform platform, int elevationBlend, int carverHorizontalResolution,
public NoiseChunkGenerator3D(Platform platform, int elevationBlend, int carverHorizontalResolution,
int carverVerticalResolution) {
this.configPack = c;
this.platform = platform;
this.air = platform.getWorldHandle().air();
this.carverHorizontalResolution = carverHorizontalResolution;
@@ -131,6 +128,11 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
} else return air;
}
@Override
public Palette getPalette(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) {
return biomeProvider.getBiome(x, z, world.getSeed()).getContext().get(PaletteInfo.class).paletteHolder().getPalette(y);
}
public SamplerProvider samplerProvider() {
return samplerCache;
}

View File

@@ -8,6 +8,7 @@
package com.dfsek.terra.api.world.chunk.generation;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.util.Palette;
import com.dfsek.terra.api.world.info.WorldProperties;
import org.jetbrains.annotations.NotNull;
@@ -15,7 +16,6 @@ import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.util.vector.Vector3Int;
import com.dfsek.terra.api.world.WritableWorld;
public interface ChunkGenerator {
@@ -31,4 +31,6 @@ public interface ChunkGenerator {
default BlockState getBlock(WorldProperties world, Vector3Int vector3, BiomeProvider biomeProvider) {
return getBlock(world, vector3.getX(), vector3.getY(), vector3.getZ(), biomeProvider);
}
Palette getPalette(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider);
}

View File

@@ -0,0 +1,178 @@
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.ChunkSectionPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.StructureWeightType;
import net.minecraft.world.gen.feature.StructureFeature;
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;
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 ObjectList<StructurePiece> pieces;
private final ObjectList<JigsawJunction> junctions;
private final ObjectListIterator<StructurePiece> pieceIterator;
private final ObjectListIterator<JigsawJunction> junctionIterator;
private final Chunk chunk;
private final int minY;
private final int maxY;
public BeardGenerator(StructureAccessor structureAccessor, Chunk chunk) {
this.chunk = chunk;
ChunkPos chunkPos = chunk.getPos();
int i = chunkPos.getStartX();
int j = chunkPos.getStartZ();
this.junctions = new ObjectArrayList<>(32);
this.pieces = new ObjectArrayList<>(10);
int minY = chunk.getBottomY();
int maxY = chunk.getTopY();
for (StructureFeature<?> structureFeature : StructureFeature.LAND_MODIFYING_STRUCTURES) {
for(StructureStart<?> start : structureAccessor.getStructureStarts(ChunkSectionPos.from(chunk), structureFeature)) {
for(StructurePiece structurePiece : start.getChildren()) {
if(!structurePiece.intersectsChunk(chunkPos, 12)) continue;
if(structurePiece instanceof PoolStructurePiece poolStructurePiece) {
Projection projection = poolStructurePiece.getPoolElement().getProjection();
if(projection == Projection.RIGID) {
this.pieces.add(poolStructurePiece);
}
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) {
continue;
}
maxY = Math.max(maxY, jigsawJunction.getSourceGroundY());
minY = Math.min(minY, jigsawJunction.getSourceGroundY());
this.junctions.add(jigsawJunction);
}
continue;
}
maxY = Math.max(maxY, structurePiece.getCenter().getY());
minY = Math.min(minY, structurePiece.getCenter().getY());
this.pieces.add(structurePiece);
}
}
}
this.pieceIterator = this.pieces.iterator();
this.junctionIterator = this.junctions.iterator();
this.minY = minY;
this.maxY = maxY;
}
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) > 0.5) {
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 noise = 0.0;
while (this.pieceIterator.hasNext()) {
StructurePiece structurePiece = this.pieceIterator.next();
BlockBox blockBox = structurePiece.getBoundingBox();
int structureX = Math.max(0, Math.max(blockBox.getMinX() - x, x - blockBox.getMaxX()));
int structureY = y - (blockBox.getMinY() + (structurePiece instanceof PoolStructurePiece ? ((PoolStructurePiece)structurePiece).getGroundLevelDelta() : 0));
int structureZ = Math.max(0, Math.max(blockBox.getMinZ() - z, z - blockBox.getMaxZ()));
StructureWeightType structureWeightType = structurePiece.getWeightType();
if (structureWeightType == StructureWeightType.BURY) {
noise += getMagnitudeWeight(structureX, structureY, structureZ);
continue;
}
if (structureWeightType != StructureWeightType.BEARD) continue;
noise += getStructureWeight(structureX, structureY, structureZ) * 0.8;
}
this.pieceIterator.back(this.pieces.size());
while (this.junctionIterator.hasNext()) {
JigsawJunction structurePiece = this.junctionIterator.next();
int structureX = x - structurePiece.getSourceX();
int structureY = y - structurePiece.getSourceGroundY();
int structureZ = z - structurePiece.getSourceZ();
noise += getStructureWeight(structureX, structureY, structureZ) * 0.4;
}
this.junctionIterator.back(this.junctions.size());
return noise;
}
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 xOffset = x + 12;
int yOffset = y + 12;
int zOffset = z + 12;
if (xOffset < 0 || xOffset >= 24) {
return 0.0;
}
if (yOffset < 0 || yOffset >= 24) {
return 0.0;
}
if (zOffset < 0 || zOffset >= 24) {
return 0.0;
}
return STRUCTURE_WEIGHT_TABLE[zOffset * 24 * 24 + xOffset * 24 + yOffset];
}
/**
* 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;
}
}

View File

@@ -43,6 +43,7 @@ import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.GenerationStep;
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.StructuresConfig;
@@ -154,14 +155,14 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
@Override
public CompletableFuture<Chunk> populateNoise(Executor executor, Blender arg, StructureAccessor structureAccessor, Chunk chunk) {
new StructureWeightSampler(structureAccessor, chunk);
return CompletableFuture.supplyAsync(() -> {
ProtoWorld world = (ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld();
delegate.generateChunkData((ProtoChunk) chunk, world, pack.getBiomeProvider().caching(), chunk.getPos().x, chunk.getPos().z);
pack.getStages().forEach(populator -> {
if(populator instanceof Chunkified) {
populator.populate(world);
}
});
BiomeProvider biomeProvider = pack.getBiomeProvider().caching();
delegate.generateChunkData((ProtoChunk) chunk, world, biomeProvider, chunk.getPos().x, chunk.getPos().z);
new BeardGenerator(structureAccessor, chunk).generate(delegate, world, biomeProvider);
return chunk;
}, executor);
}

View File

@@ -1,3 +1,5 @@
accessWidener v1 named
extendable method net/minecraft/client/world/GeneratorType <init> (Ljava/lang/String;)V
accessible method net/minecraft/world/gen/StructureWeightSampler <init> (Lnet/minecraft/world/gen/StructureAccessor;Lnet/minecraft/world/chunk/Chunk;)V