Add compute_density_function to replace removed `sample_noise (#1591)

This commit is contained in:
Crec0 authored and GitHub committed 2023-01-25 17:08:36 +01:00
1 parent d26a56ea98
commit f2c658bf03
10 files changed
+141 -318

No files matched your search

+31 -15
View File
@@ -509,30 +509,46 @@ Returns the map colour of a block at position. One of:
`'brown_terracotta'`, `'green_terracotta'`, `'red_terracotta'`, `'black_terracotta'`,
`'crimson_nylium'`, `'crimson_stem'`, `'crimson_hyphae'`, `'warped_nylium'`, `'warped_stem'`, `'warped_hyphae'`, `'warped_wart'`
### `sample_noise(pos, ...type?)` 1.18+ only
### `compute_density_function(pos, ...types?)` 1.19+ only
Samples the multi noise value(s) on the given position.
If no type is passed, returns a map of `continentalness`, `depth`, `erosion`, `humidity`, `temperature`, `weirdness`.
Otherwise, returns the map of that specific noise.
**Note: Replaces the old `sample_noise` function**
Computes the density function(s) on the given position. Check the [Available Types](#available-types) for list of available density functions.
If no types are passed in, it returns a list of all the available density functions. Built-in and custom ones.
<pre>
// without type
sample_noise(pos) => {continentalness: 0.445300012827, erosion: 0.395399987698, temperature: 0.165399998426, ...}
// passing type as multiple arguments
sample_noise(pos, 'pillarRareness', 'aquiferBarrier') => {aquiferBarrier: -0.205013844481, pillarRareness: 1.04772473438}
compute_density_function(pos, 'continents', 'depth') => {continents: -0.205013844481, depth: 1.04772473438}
// passing types as a list with unpacking operator
sample_noise(pos, ...['spaghetti3dFirst', 'spaghetti3dSecond']) => {spaghetti3dFirst: -0.186052125186, spaghetti3dSecond: 0.211626790923}
compute_density_function(pos, ...['ridges', 'overworld/caves/pillars']) => {ridges: -0.186052125186, overworld/caves/pillars: 0.211626790923}
// Custom Defined types
compute_density_function(pos, 'mydatapack:my_density_func') => {mydatapack:my_density_func: -0.186052125186}
</pre>
Available types:
#### Available types:
`aquiferBarrier`, `aquiferFluidLevelFloodedness`, `aquiferFluidLevelSpread`, `aquiferLava`, `caveCheese`,
`caveEntrance`, `caveLayer`, `continentalness`, `depth`, `erosion`, `humidity`, `island`, `jagged`, `oreGap`,
`pillar`, `pillarRareness`, `pillarThickness`, `shiftX`, `shiftY`, `shiftZ`, `spaghetti2d`, `spaghetti2dElevation`,
`spaghetti2dModulator`, `spaghetti2dThickness`, `spaghetti3d`, `spaghetti3dFirst`, `spaghetti3dRarity`,
`spaghetti3dSecond`, `spaghetti3dThickness`, `spaghettiRoughness`, `spaghettiRoughnessModulator`, `temperature`,
`terrain`, `terrainFactor`, `terrainOffset`, `terrainPeaks`, `weirdness`
##### Built-in
`'barrier_noise'`, `'continents'`, `'depth'`, `'end/base_3d_noise'`, `'end/sloped_cheese'`, `'erosion'`, `'final_density'`,
`'fluid_level_floodedness_noise'`, `'fluid_level_spread_noise'`, `'initial_density_without_jaggedness'`, `'lava_noise'`,
`'nether/base_3d_noise'`, `'overworld/base_3d_noise'`, `'overworld/base_continents'`, `'overworld/caves/entrances'`,
`'overworld/caves/noodle'`, `'overworld/caves/pillars'`, `'overworld/caves/spaghetti_2d'`, `'overworld/caves/spaghetti_2d_thickness_modulator'`,
`'overworld/caves/spaghetti_roughness_function'`, `'overworld/continents'`, `'overworld/depth'`, `'overworld/erosion'`,
`'overworld/factor'`, `'overworld/jaggedness'`, `'overworld/offset'`, `'overworld/ridges'`, `'overworld/ridges_folded'`,
`'overworld/sloped_cheese'`, `'overworld_amplified/depth'`, `'overworld_amplified/factor'`, `'overworld_amplified/jaggedness'`,
`'overworld_amplified/offset'`, `'overworld_amplified/sloped_cheese'`, `'overworld_large_biomes/base_continents'`,
`'overworld_large_biomes/continents'`, `'overworld_large_biomes/depth'`, `'overworld_large_biomes/erosion'`,
`'overworld_large_biomes/factor'`, `'overworld_large_biomes/jaggedness'`, `'overworld_large_biomes/offset'`,
`'overworld_large_biomes/sloped_cheese'`, `'ridges'`, `'shift_x'`, `'shift_z'`, `'temperature'`, `'vegetation'`,
`'vein_gap'`, `'vein_gapbarrier_noise'`, `'vein_ridged'`, `'vein_toggle'`, `'y'`, `'zero'`
##### Custom
Custom defined density functions from datapacks are also available and can be used. However, unlike built-in types, these
ones must use full namespace. i.e. `namespace:path`. Examples: `'mydatapack:density_function'`, `'mydatapack:nested/density_function'`
**Note: Custom density functions require a server relaunch after enabling the datapack.**
### `loaded(pos)`
+1 -1
View File
@@ -93,7 +93,7 @@ reload_chunk
remove_all_markers
reset_chunk
run
sample_noise
compute_density_function
save
scan
schedule
@@ -57,7 +57,7 @@
hardness blast_resistance top loaded suffocates power ticks_randomly update block_tick random_tick in_slime_chunk
set without_updates
blocks_movement block_sound material map_colour block_state block_list block_tags block_data poi set_poi
place_item set_biome biome loaded_status generation_status sample_noise inhabited_time spawn_potential chunk_tickets
place_item set_biome biome loaded_status generation_status compute_density_function inhabited_time spawn_potential chunk_tickets
plop harvest destroy create_explosion
structure_eligibility structures structure_references set_structure
reset_chunk reload_chunk create_datapack
@@ -1,5 +0,0 @@
package carpet.fakes;
public interface NoiseColumnSamplerInterface {
double getNoiseSample(String name, int x, int y, int z);
}
@@ -0,0 +1,7 @@
package carpet.fakes;
import net.minecraft.world.level.levelgen.DensityFunction;
public interface RandomStateVisitorAccessor {
DensityFunction.Visitor getVisitor();
}
@@ -1,265 +0,0 @@
package carpet.mixins;
import carpet.fakes.NoiseColumnSamplerInterface;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.core.QuartPos;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.levelgen.NoiseRouter;
import net.minecraft.world.level.levelgen.NoiseRouterData;
//import net.minecraft.world.level.levelgen.NoiseSampler;
import net.minecraft.world.level.levelgen.NoiseSettings;
//import net.minecraft.world.level.levelgen.TerrainInfo;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.synth.BlendedNoise;
import net.minecraft.world.level.levelgen.synth.NoiseUtils;
import net.minecraft.world.level.levelgen.synth.NormalNoise;
import net.minecraft.world.level.levelgen.synth.SimplexNoise;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(NoiseRouterData.class)
public abstract class NoiseSampler_scarpetMixin implements NoiseColumnSamplerInterface {
/*
@Shadow @Final
private NoiseRouter router;
@Shadow @Final
private BlendedNoise blendedNoise;
@Shadow @Final @Nullable
private SimplexNoise islandNoise;
@Shadow @Final
private NormalNoise barrierNoise;
@Shadow @Final
private NormalNoise fluidLevelFloodednessNoise;
@Shadow @Final
private NormalNoise fluidLevelSpreadNoise;
@Shadow @Final
private NormalNoise lavaNoise;
@Shadow @Final
private NormalNoise pillarRarenessModulator;
@Shadow @Final
private NormalNoise pillarThicknessModulator;
@Shadow @Final
private NormalNoise spaghetti2DElevationModulator;
@Shadow @Final
private NormalNoise spaghetti2DRarityModulator;
@Shadow @Final
private NormalNoise spaghetti2DThicknessModulator;
@Shadow @Final
private NormalNoise spaghetti3DNoiseSource1;
@Shadow @Final
private NormalNoise spaghetti3DNoiseSource2;
@Shadow @Final
private NormalNoise spaghetti3DRarityModulator;
@Shadow @Final
private NormalNoise spaghetti3DThicknessModulator;
@Shadow @Final
private NormalNoise spaghettiRoughnessModulator;
@Shadow @Final
private NormalNoise cheeseNoiseSource;
@Shadow @Final
private NormalNoise gapNoise;
@Shadow @Final
private NoiseSettings noiseSettings;
@Shadow
protected abstract double sampleJaggedNoise(double d, double e, double f);
@Shadow
protected abstract double getLayerizedCaverns(int x, int y, int z);
@Shadow
protected abstract double getPillars(int x, int y, int z);
@Shadow
protected abstract double getSpaghetti2D(int x, int y, int z);
@Shadow
protected abstract double getSpaghetti3D(int x, int y, int z);
@Shadow
protected abstract double spaghettiRoughness(int x, int y, int z);
@Shadow
protected abstract double getBigEntrances(int x, int y, int z);
@Shadow
public abstract double getOffset(int x, int y, int z);
@Shadow
private static double sampleWithRarity(NormalNoise sampler, double x, double y, double z, double invertedScale) {
throw new AssertionError();
}
@Shadow
public abstract Climate.TargetPoint sample(int i, int j, int k);
@Shadow
public abstract TerrainInfo terrainInfo(int x, int z, float continentalness, float weirdness, float erosion, Blender blender);
@Override
public double getNoiseSample(String name, int x, int y, int z) {
Climate.TargetPoint noiseValuePoint = this.sample(x, y, z);
TerrainInfo terrainNoisePoint = terrainInfo(
x,
z,
Climate.unquantizeCoord(noiseValuePoint.continentalness()),
Climate.unquantizeCoord(noiseValuePoint.weirdness()),
Climate.unquantizeCoord(noiseValuePoint.erosion()),
Blender.empty()
);
switch (name) {
case "temperature" -> {
return Climate.unquantizeCoord(noiseValuePoint.temperature());
}
case "humidity" -> {
return Climate.unquantizeCoord(noiseValuePoint.humidity());
}
case "continentalness" -> {
return Climate.unquantizeCoord(noiseValuePoint.continentalness());
}
case "erosion" -> {
return Climate.unquantizeCoord(noiseValuePoint.erosion());
}
case "weirdness" -> {
return Climate.unquantizeCoord(noiseValuePoint.weirdness());
}
case "depth" -> {
return Climate.unquantizeCoord(noiseValuePoint.depth());
}
case "shiftX" -> {
return x + this.getOffset(x, 0, z);
}
case "shiftY" -> {
return y + this.getOffset(y, z, x);
}
case "shiftZ" -> {
return z + this.getOffset(z, x, 0);
}
case "terrain" -> {
return this.blendedNoise.calculateNoise(x, y, z);
}
case "island" -> {
return this.islandNoise == null ? 0 : this.islandNoise.getValue(x, y, z);
}
case "jagged" -> {
return this.sampleJaggedNoise(terrainNoisePoint.jaggedness(), x, z);
}
case "aquiferBarrier" -> {
return this.barrierNoise.getValue(x, y, z);
}
case "aquiferFluidLevelFloodedness" -> {
return this.fluidLevelFloodednessNoise.getValue(x, y, z);
}
case "aquiferFluidLevelSpread" -> {
return this.fluidLevelSpreadNoise.getValue(x, y, z);
}
case "aquiferLava" -> {
return this.lavaNoise.getValue(x, y, z);
}
case "pillar" -> {
return this.getPillars(x, y, z);
}
case "pillarRareness" -> {
return NoiseUtils.sampleNoiseAndMapToRange(this.pillarRarenessModulator, x, y, z, 0.0D, 2.0D);
}
case "pillarThickness" -> {
return NoiseUtils.sampleNoiseAndMapToRange(this.pillarThicknessModulator, x, y, z, 0.0D, 1.1D);
}
case "spaghetti2d" -> {
return this.getSpaghetti2D(x, y, z);
}
case "spaghetti2dElevation" -> {
return NoiseUtils.sampleNoiseAndMapToRange(this.spaghetti2DElevationModulator, x, 0.0, z, this.noiseSettings.getMinCellY(), 8.0);
}
case "spaghetti2dModulator" -> {
return this.spaghetti2DRarityModulator.getValue(x * 2, y, z * 2);
}
case "spaghetti2dThickness" -> {
return NoiseUtils.sampleNoiseAndMapToRange(this.spaghetti2DThicknessModulator, x * 2, y, z * 2, 0.6, 1.3);
}
case "spaghetti3d" -> {
return this.getSpaghetti3D(x, y, z);
}
case "spaghetti3dFirst" -> {
double d = this.spaghetti3DRarityModulator.getValue(x * 2, y, z * 2);
double e = QuantizedSpaghettiRarityMixin_scarpetMixin.invokeGetSpaghettiRarity3D(d);
return sampleWithRarity(this.spaghetti3DNoiseSource1, x, y, z, e);
}
case "spaghetti3dSecond" -> {
double d = this.spaghetti3DRarityModulator.getValue(x * 2, y, z * 2);
double e = QuantizedSpaghettiRarityMixin_scarpetMixin.invokeGetSpaghettiRarity3D(d);
return sampleWithRarity(this.spaghetti3DNoiseSource2, x, y, z, e);
}
case "spaghetti3dRarity" -> {
return this.spaghetti3DRarityModulator.getValue(x * 2, y, z * 2);
}
case "spaghetti3dThickness" -> {
return NoiseUtils.sampleNoiseAndMapToRange(this.spaghetti3DThicknessModulator, x, y, z, 0.065, 0.088);
}
case "spaghettiRoughness" -> {
return this.spaghettiRoughness(x, y, z);
}
case "spaghettiRoughnessModulator" -> {
return NoiseUtils.sampleNoiseAndMapToRange(this.spaghettiRoughnessModulator, x, y, z, 0.0, 0.1);
}
case "caveEntrance" -> {
return this.getBigEntrances(
QuartPos.toBlock(x),
QuartPos.toBlock(y),
QuartPos.toBlock(z)
);
}
case "caveLayer" -> {
// scaling them by 4 because it's sampled in normal coords
return this.getLayerizedCaverns(
QuartPos.toBlock(x),
QuartPos.toBlock(y),
QuartPos.toBlock(z)
);
}
case "caveCheese" -> {
// same reason as above
return this.cheeseNoiseSource.getValue(
QuartPos.toBlock(x),
QuartPos.toBlock(y) / 1.5,
QuartPos.toBlock(z)
);
}
case "terrainPeaks" -> {
return terrainNoisePoint.jaggedness();
}
case "terrainOffset" -> {
return terrainNoisePoint.offset();
}
case "terrainFactor" -> {
return terrainNoisePoint.factor();
}
case "oreGap" -> {
return this.gapNoise.getValue(x, y, z);
}
}
throw new InternalExpressionException("Unknown noise type: " + name);
}*/
}
@@ -1,15 +0,0 @@
package carpet.mixins;
//import net.minecraft.world.level.levelgen.NoiseRouterData;
//import net.minecraft.world.level.levelgen.NoiseSampler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(targets = "net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity")
public interface QuantizedSpaghettiRarityMixin_scarpetMixin {
@Invoker
static double invokeGetSpaghettiRarity3D(double d) {
throw new AssertionError();
}
}
@@ -0,0 +1,33 @@
package carpet.mixins;
import carpet.fakes.RandomStateVisitorAccessor;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.RandomState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(RandomState.class)
public class RandomState_ScarpetMixin implements RandomStateVisitorAccessor {
@Unique
private DensityFunction.Visitor visitor;
@ModifyArg(
method = "<init>",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/levelgen/NoiseRouter;mapAll(Lnet/minecraft/world/level/levelgen/DensityFunction$Visitor;)Lnet/minecraft/world/level/levelgen/NoiseRouter;"
),
index = 0
)
private DensityFunction.Visitor captureVisitor(DensityFunction.Visitor visitor) {
this.visitor = visitor;
return visitor;
}
@Override
public DensityFunction.Visitor getVisitor() {
return this.visitor;
}
}
@@ -3,6 +3,7 @@ package carpet.script.api;
import carpet.CarpetSettings;
import carpet.fakes.ChunkGeneratorInterface;
import carpet.fakes.ChunkTicketManagerInterface;
import carpet.fakes.RandomStateVisitorAccessor;
import carpet.fakes.ServerChunkManagerInterface;
import carpet.fakes.ServerWorldInterface;
import carpet.fakes.SpawnHelperInnerInterface;
@@ -41,15 +42,22 @@ import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.HolderSet;
import net.minecraft.core.QuartPos;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseRouter;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureType;
import net.minecraft.world.level.levelgen.synth.NormalNoise;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -1626,23 +1634,68 @@ public class WorldAccess {
}
@ScarpetFunction(maxParams = -1)
public Value sample_noise(Context c, @Locator.Block BlockPos pos, String... noiseQueries) {
return Value.NULL;
/*
int mappedX = QuartPos.fromBlock(pos.getX());
int mappedY = QuartPos.fromBlock(pos.getY());
int mappedZ = QuartPos.fromBlock(pos.getZ());
Climate.Sampler mns = ((CarpetContext) c).s.getLevel().getChunkSource().getGenerator().climateSampler();
Map<Value, Value> ret = new HashMap<>();
public Value compute_density_function(Context c, @Locator.Block BlockPos pos, String... densityFunctionQueries) {
if (noiseQueries.length == 0) {
noiseQueries = new String[]{"continentalness", "erosion", "weirdness", "temperature", "humidity", "depth"};
Map<Value, Value> result = new HashMap<>();
ServerLevel level = ((CarpetContext) c).level();
Registry<DensityFunction> densityFunctionRegistry = level.registryAccess().registryOrThrow(Registries.DENSITY_FUNCTION);
if (densityFunctionQueries.length == 0) {
return ListValue.wrap(densityFunctionRegistry.keySet().stream().map(ValueConversions::of));
}
for (String noise : noiseQueries) {
double noiseValue = ((NoiseColumnSamplerInterface) mns).getNoiseSample(noise, mappedX, mappedY, mappedZ);
ret.put(new StringValue(noise), new NumericValue(noiseValue));
ChunkGenerator chunkGenerator = level.getChunkSource().getGenerator();
if (!(chunkGenerator instanceof NoiseBasedChunkGenerator generator)) {
return MapValue.wrap(result);
}
return MapValue.wrap(ret);*/
RandomState randomState = RandomState.create(
generator.generatorSettings().value(),
level.registryAccess().lookupOrThrow(Registries.NOISE), level.getSeed()
);
DensityFunction.Visitor visitor = ((RandomStateVisitorAccessor) (Object) randomState).getVisitor();
DensityFunction.SinglePointContext singlePointContext = new DensityFunction.SinglePointContext(pos.getX(), pos.getY(), pos.getZ());
NoiseRouter router = generator.generatorSettings().value().noiseRouter();
for (String densityFunctionQuery : densityFunctionQueries) {
DensityFunction densityFunction = switch (densityFunctionQuery) {
case "barrier_noise" -> router.barrierNoise();
case "fluid_level_floodedness_noise" -> router.fluidLevelFloodednessNoise();
case "fluid_level_spread_noise" -> router.fluidLevelSpreadNoise();
case "lava_noise" -> router.lavaNoise();
case "temperature" -> router.temperature();
case "vegetation" -> router.vegetation();
case "continents" -> router.continents();
case "erosion" -> router.erosion();
case "depth" -> router.depth();
case "ridges" -> router.ridges();
case "initial_density_without_jaggedness" -> router.initialDensityWithoutJaggedness();
case "final_density" -> router.finalDensity();
case "vein_toggle" -> router.veinToggle();
case "vein_ridged" -> router.veinRidged();
case "vein_gap" -> router.veinGap();
default -> {
ResourceLocation densityFunctionKey = InputValidator.identifierOf(densityFunctionQuery);
if (densityFunctionRegistry.containsKey(densityFunctionKey)) {
yield densityFunctionRegistry.get(densityFunctionKey);
}
throw new InternalExpressionException(
"Density function '" + densityFunctionQuery + "' doesn't exist. " +
"Please check the spelling or use with full 'namespace:value' if its custom defined."
);
}
};
if (densityFunction == null) // IDE thinks may be null as Registry.get is Nullable, but we checked it
throw new IllegalStateException("density function can't be null here");
double value = densityFunction.mapAll(visitor).compute(singlePointContext);
result.put(StringValue.of(densityFunctionQuery), new NumericValue(value));
}
return MapValue.wrap(result);
}
}
+1 -2
View File
@@ -162,8 +162,7 @@
"BlockPredicate_scarpetMixin",
"TagPredicate_scarpetMixin",
"HorseBaseEntity_scarpetMixin",
"NoiseSampler_scarpetMixin",
"QuantizedSpaghettiRarityMixin_scarpetMixin",
"RandomState_ScarpetMixin",
"Biome_scarpetMixin",
"BlockEntity_movableBEMixin",