mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-12 18:56:04 +00:00
add beardification support
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user