Multi noise support for scarpet (#1176)

* fix: infinite params bug in AnnotationParser
feat: scarpet function query_noise()

* refactor: remove Method reflection

* fix: use BiomeCoords

* update: game version to 1.18-pre5

* feat: biome lookup from multinoise
fix: noise lookup wrongly scaled

* fix: jagged noise. Thanks, @Starmute

* fix: cave cheese and layer. Thanks, @Starmute

* fix: revert formatting
fix: caveLayer and caveCheese
feat: add terrain support

* more formatting reverts

* fix mapping issue

* use BlockPos

* docs: add documentation for query_noise

* docs: add documentation for biome(noise_map)
This commit is contained in:
Crec0 authored and GitHub committed 2021-11-30 02:47:28 +01:00
1 parent 6c7ac72c3e
commit aa57b586cb
8 files changed
+388 -9

No files matched your search

+27 -1
View File
@@ -346,12 +346,15 @@ poi(x,y,z,5) => [] // nothing around
poi(x,y,z,5) => [['nether_portal',0,[7,8,9]],['nether_portal',0,[7,9,9]]] // two portal blocks in the range poi(x,y,z,5) => [['nether_portal',0,[7,8,9]],['nether_portal',0,[7,9,9]]] // two portal blocks in the range
</pre> </pre>
### `biome()` `biome(name)` `biome(block)` `biome(block/name, feature)` ### `biome()` `biome(name)` `biome(block)` `biome(block/name, feature)`, `biome(noise_map)`
Without arguments, returns the list of biomes in the world. Without arguments, returns the list of biomes in the world.
With block, or name, returns the name of the biome in that position, or throws `'unknown_biome'` if provided biome or block are not valid. With block, or name, returns the name of the biome in that position, or throws `'unknown_biome'` if provided biome or block are not valid.
if passed a map of `continentalness`, `depth`, `erosion`, `humidity`, `temperature`, `weirdness`, returns the biome that exists at those noise values.
Note: Have to pass all 6 of the mentioned noise types and only these noise types for it to evaluate a biome.
With an optional feature, it returns value for the specified attribute for that biome. Available and queryable features include: With an optional feature, it returns value for the specified attribute for that biome. Available and queryable features include:
* `'top_material'`: unlocalized block representing the top surface material * `'top_material'`: unlocalized block representing the top surface material
* `'under_material'`: unlocalized block representing what sits below topsoil * `'under_material'`: unlocalized block representing what sits below topsoil
@@ -502,6 +505,29 @@ Returns the map colour of a block at position. One of:
`'brown_terracotta'`, `'green_terracotta'`, `'red_terracotta'`, `'black_terracotta'`, `'brown_terracotta'`, `'green_terracotta'`, `'red_terracotta'`, `'black_terracotta'`,
`'crimson_nylium'`, `'crimson_stem'`, `'crimson_hyphae'`, `'warped_nylium'`, `'warped_stem'`, `'warped_hyphae'`, `'warped_wart'` `'crimson_nylium'`, `'crimson_stem'`, `'crimson_hyphae'`, `'warped_nylium'`, `'warped_stem'`, `'warped_hyphae'`, `'warped_wart'`
### `query_noise(pos, ...type?)`
Queries 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.
<pre>
// without type
query_noise(pos) => {continentalness: 0.445300012827, erosion: 0.395399987698, temperature: 0.165399998426, ...}
// passing type as multiple arguments
query_noise(pos, 'pillarRareness', 'aquiferBarrier') => {aquiferBarrier: -0.205013844481, pillarRareness: 1.04772473438}
// passing types as a list with unpacking operator
query_noise(pos, ...['spaghetti3dFirst', 'spaghetti3dSecond']) => {spaghetti3dFirst: -0.186052125186, spaghetti3dSecond: 0.211626790923}
</pre>
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`
### `loaded(pos)` ### `loaded(pos)`
@@ -0,0 +1,5 @@
package carpet.fakes;
public interface NoiseColumnSamplerInterface {
double getNoiseSample(String name, int x, int y, int z);
}
@@ -0,0 +1,14 @@
package carpet.mixins;
import net.minecraft.world.gen.NoiseColumnSampler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(NoiseColumnSampler.CaveScaler.class)
public interface CaveScalerMixin_scarpetMixin {
@Invoker
static double invokeScaleTunnels(double d) {
throw new AssertionError();
}
}
@@ -0,0 +1,255 @@
package carpet.mixins;
import carpet.fakes.NoiseColumnSamplerInterface;
import carpet.script.exception.InternalExpressionException;
import net.minecraft.util.math.noise.DoublePerlinNoiseSampler;
import net.minecraft.util.math.noise.InterpolatedNoiseSampler;
import net.minecraft.util.math.noise.SimplexNoiseSampler;
import net.minecraft.world.biome.source.BiomeCoords;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import net.minecraft.world.biome.source.util.TerrainNoisePoint;
import net.minecraft.world.gen.NoiseColumnSampler;
import net.minecraft.world.gen.NoiseHelper;
import net.minecraft.world.gen.chunk.Blender;
import net.minecraft.world.gen.chunk.GenerationShapeConfig;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(NoiseColumnSampler.class)
public abstract class NoiseColumnSamplerMixin_scarpetMixin implements NoiseColumnSamplerInterface {
@Shadow @Final
private InterpolatedNoiseSampler terrainNoise;
@Shadow @Final @Nullable
private SimplexNoiseSampler islandNoise;
@Shadow @Final
private DoublePerlinNoiseSampler aquiferBarrierNoise;
@Shadow @Final
private DoublePerlinNoiseSampler aquiferFluidLevelFloodednessNoise;
@Shadow @Final
private DoublePerlinNoiseSampler aquiferFluidLevelSpreadNoise;
@Shadow @Final
private DoublePerlinNoiseSampler aquiferLavaNoise;
@Shadow @Final
private DoublePerlinNoiseSampler pillarRarenessNoise;
@Shadow @Final
private DoublePerlinNoiseSampler pillarThicknessNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghetti2dElevationNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghetti2dModulatorNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghetti2dThicknessNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghetti3dFirstNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghetti3dSecondNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghetti3dRarityNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghetti3dThicknessNoise;
@Shadow @Final
private DoublePerlinNoiseSampler spaghettiRoughnessModulatorNoise;
@Shadow @Final
private DoublePerlinNoiseSampler caveCheeseNoise;
@Shadow @Final
private DoublePerlinNoiseSampler oreGapNoise;
@Shadow @Final
private GenerationShapeConfig config;
@Shadow
protected abstract double method_38409(double d, double e, double f);
@Shadow
protected abstract double sampleCaveLayerNoise(int x, int y, int z);
@Shadow
protected abstract double samplePillarNoise(int x, int y, int z);
@Shadow
protected abstract double sampleSpaghetti2dNoise(int x, int y, int z);
@Shadow
protected abstract double sampleSpaghetti3dNoise(int x, int y, int z);
@Shadow
protected abstract double sampleSpaghettiRoughnessNoise(int x, int y, int z);
@Shadow
protected abstract double sampleCaveEntranceNoise(int x, int y, int z);
@Shadow
public abstract double sampleShiftNoise(int x, int y, int z);
@Shadow
private static double sample(DoublePerlinNoiseSampler sampler, double x, double y, double z, double invertedScale) {
throw new AssertionError();
}
@Shadow
public abstract MultiNoiseUtil.NoiseValuePoint sample(int i, int j, int k);
@Shadow
public abstract TerrainNoisePoint createTerrainNoisePoint(int x, int z, float continentalness, float weirdness, float erosion, Blender blender);
@Override
public double getNoiseSample(String name, int x, int y, int z) {
MultiNoiseUtil.NoiseValuePoint noiseValuePoint = this.sample(x, y, z);
TerrainNoisePoint terrainNoisePoint = createTerrainNoisePoint(
x,
z,
MultiNoiseUtil.method_38666(noiseValuePoint.continentalnessNoise()),
MultiNoiseUtil.method_38666(noiseValuePoint.weirdnessNoise()),
MultiNoiseUtil.method_38666(noiseValuePoint.erosionNoise()),
Blender.getNoBlending()
);
switch (name) {
case "temperature" -> {
return MultiNoiseUtil.method_38666(noiseValuePoint.temperatureNoise());
}
case "humidity" -> {
return MultiNoiseUtil.method_38666(noiseValuePoint.humidityNoise());
}
case "continentalness" -> {
return MultiNoiseUtil.method_38666(noiseValuePoint.continentalnessNoise());
}
case "erosion" -> {
return MultiNoiseUtil.method_38666(noiseValuePoint.erosionNoise());
}
case "weirdness" -> {
return MultiNoiseUtil.method_38666(noiseValuePoint.weirdnessNoise());
}
case "depth" -> {
return MultiNoiseUtil.method_38666(noiseValuePoint.depth());
}
case "shiftX" -> {
return x + this.sampleShiftNoise(x, 0, z);
}
case "shiftY" -> {
return y + this.sampleShiftNoise(y, z, x);
}
case "shiftZ" -> {
return z + this.sampleShiftNoise(z, x, 0);
}
case "terrain" -> {
return this.terrainNoise.calculateNoise(x, y, z);
}
case "island" -> {
return this.islandNoise == null ? 0 : this.islandNoise.sample(x, y, z);
}
case "jagged" -> {
return this.method_38409(terrainNoisePoint.peaks(), x, z);
}
case "aquiferBarrier" -> {
return this.aquiferBarrierNoise.sample(x, y, z);
}
case "aquiferFluidLevelFloodedness" -> {
return this.aquiferFluidLevelFloodednessNoise.sample(x, y, z);
}
case "aquiferFluidLevelSpread" -> {
return this.aquiferFluidLevelSpreadNoise.sample(x, y, z);
}
case "aquiferLava" -> {
return this.aquiferLavaNoise.sample(x, y, z);
}
case "pillar" -> {
return this.samplePillarNoise(x, y, z);
}
case "pillarRareness" -> {
return NoiseHelper.lerpFromProgress(this.pillarRarenessNoise, x, y, z, 0.0D, 2.0D);
}
case "pillarThickness" -> {
return NoiseHelper.lerpFromProgress(this.pillarThicknessNoise, x, y, z, 0.0D, 1.1D);
}
case "spaghetti2d" -> {
return this.sampleSpaghetti2dNoise(x, y, z);
}
case "spaghetti2dElevation" -> {
return NoiseHelper.lerpFromProgress(this.spaghetti2dElevationNoise, x, 0.0, z, this.config.minimumBlockY(), 8.0);
}
case "spaghetti2dModulator" -> {
return this.spaghetti2dModulatorNoise.sample(x * 2, y, z * 2);
}
case "spaghetti2dThickness" -> {
return NoiseHelper.lerpFromProgress(this.spaghetti2dThicknessNoise, x * 2, y, z * 2, 0.6, 1.3);
}
case "spaghetti3d" -> {
return this.sampleSpaghetti3dNoise(x, y, z);
}
case "spaghetti3dFirst" -> {
double d = this.spaghetti3dRarityNoise.sample(x * 2, y, z * 2);
double e = CaveScalerMixin_scarpetMixin.invokeScaleTunnels(d);
return sample(this.spaghetti3dFirstNoise, x, y, z, e);
}
case "spaghetti3dSecond" -> {
double d = this.spaghetti3dRarityNoise.sample(x * 2, y, z * 2);
double e = CaveScalerMixin_scarpetMixin.invokeScaleTunnels(d);
return sample(this.spaghetti3dSecondNoise, x, y, z, e);
}
case "spaghetti3dRarity" -> {
return this.spaghetti3dRarityNoise.sample(x * 2, y, z * 2);
}
case "spaghetti3dThickness" -> {
return NoiseHelper.lerpFromProgress(this.spaghetti3dThicknessNoise, x, y, z, 0.065, 0.088);
}
case "spaghettiRoughness" -> {
return this.sampleSpaghettiRoughnessNoise(x, y, z);
}
case "spaghettiRoughnessModulator" -> {
return NoiseHelper.lerpFromProgress(this.spaghettiRoughnessModulatorNoise, x, y, z, 0.0, 0.1);
}
case "caveEntrance" -> {
return this.sampleCaveEntranceNoise(x, y, z);
}
case "caveLayer" -> {
// scaling them by 4 because it's sampled in normal coords
return this.sampleCaveLayerNoise(
BiomeCoords.toBlock(x),
BiomeCoords.toBlock(y),
BiomeCoords.toBlock(z)
);
}
case "caveCheese" -> {
// same reason as above
return this.caveCheeseNoise.sample(
BiomeCoords.toBlock(x),
BiomeCoords.toBlock(y) / 1.5,
BiomeCoords.toBlock(z)
);
}
case "terrainPeaks" -> {
return terrainNoisePoint.peaks();
}
case "terrainOffset" -> {
return terrainNoisePoint.offset();
}
case "terrainFactor" -> {
return terrainNoisePoint.factor();
}
case "oreGap" -> {
return this.oreGapNoise.sample(x, y, z);
}
}
throw new InternalExpressionException("Unknown noise type: " + name);
}
}
@@ -189,11 +189,11 @@ public final class AnnotationParser
if (maxParams == -2) if (maxParams == -2)
throw new IllegalArgumentException("No maximum number of params specified for " + name + ", use -1 for unlimited. " throw new IllegalArgumentException("No maximum number of params specified for " + name + ", use -1 for unlimited. "
+ "Provided in " + instance.getClass()); + "Provided in " + instance.getClass());
if (maxParams == -1)
maxParams = Integer.MAX_VALUE;
if (maxParams < this.minParams) if (maxParams < this.minParams)
throw new IllegalArgumentException("Provided maximum number of params for " + name + " is smaller than method's param count." throw new IllegalArgumentException("Provided maximum number of params for " + name + " is smaller than method's param count."
+ "Provided in " + instance.getClass()); + "Provided in " + instance.getClass());
if (maxParams == -1)
maxParams = Integer.MAX_VALUE;
} }
this.maxParams = maxParams; this.maxParams = maxParams;
@@ -5,6 +5,7 @@ import carpet.CarpetSettings;
import carpet.fakes.BiomeArrayInterface; import carpet.fakes.BiomeArrayInterface;
import carpet.fakes.ChunkGeneratorInterface; import carpet.fakes.ChunkGeneratorInterface;
import carpet.fakes.ChunkTicketManagerInterface; import carpet.fakes.ChunkTicketManagerInterface;
import carpet.fakes.NoiseColumnSamplerInterface;
import carpet.fakes.ServerChunkManagerInterface; import carpet.fakes.ServerChunkManagerInterface;
import carpet.fakes.ServerWorldInterface; import carpet.fakes.ServerWorldInterface;
import carpet.fakes.SpawnHelperInnerInterface; import carpet.fakes.SpawnHelperInnerInterface;
@@ -16,6 +17,8 @@ import carpet.script.Context;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.Fluff; import carpet.script.Fluff;
import carpet.script.LazyValue; import carpet.script.LazyValue;
import carpet.script.annotation.Locator;
import carpet.script.annotation.ScarpetFunction;
import carpet.script.argument.BlockArgument; import carpet.script.argument.BlockArgument;
import carpet.script.argument.Vector3Argument; import carpet.script.argument.Vector3Argument;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
@@ -93,6 +96,9 @@ import net.minecraft.world.SpawnHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.source.BiomeCoords; import net.minecraft.world.biome.source.BiomeCoords;
import net.minecraft.world.biome.source.BiomeSource;
import net.minecraft.world.biome.source.MultiNoiseBiomeSource;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.chunk.WorldChunk;
@@ -221,6 +227,20 @@ public class WorldAccess {
return bs; return bs;
} }
private static void nullCheck(Value v, String name) {
if (v.isNull()) {
throw new IllegalArgumentException(name + " cannot be null");
}
}
private static float numberGetOrThrow(Value v) {
double num = v.readDoubleNumber();
if (Double.isNaN(num)) {
throw new IllegalArgumentException(v.getString() + " needs to be a numeric value");
}
return (float) num;
}
private static void BooYah(ChunkGenerator generator) private static void BooYah(ChunkGenerator generator)
{ {
synchronized (generator) synchronized (generator)
@@ -343,7 +363,7 @@ public class WorldAccess {
} }
String poiTypeString = poi.getString().toLowerCase(Locale.ROOT); String poiTypeString = poi.getString().toLowerCase(Locale.ROOT);
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(InputValidator.identifierOf(poiTypeString)) PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(InputValidator.identifierOf(poiTypeString))
.orElseThrow(() -> new ThrowStatement(poiTypeString, Throwables.UNKNOWN_POI)); .orElseThrow(() -> new ThrowStatement(poiTypeString, Throwables.UNKNOWN_POI));
int occupancy = 0; int occupancy = 0;
if (locator.offset + 1 < lv.size()) if (locator.offset + 1 < lv.size())
{ {
@@ -1129,19 +1149,55 @@ public class WorldAccess {
return BooleanValue.of(blockLocator.block.getBlockState().isIn(blockTag)); return BooleanValue.of(blockLocator.block.getBlockState().isIn(blockTag));
}); });
expression.addContextFunction("biome", -1, (c, t, lv) -> { expression.addContextFunction("biome", -1, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext) c;
ServerWorld world = cc.s.getWorld(); ServerWorld world = cc.s.getWorld();
if (lv.size() == 0) if (lv.size() == 0)
return ListValue.wrap(world.getRegistryManager().get(Registry.BIOME_KEY).getIds().stream().map(ValueConversions::of)); return ListValue.wrap(world.getRegistryManager().get(Registry.BIOME_KEY).getIds().stream().map(ValueConversions::of));
BlockArgument locator = BlockArgument.findIn(cc, lv, 0, false, false, true);
Biome biome; Biome biome;
BiomeSource biomeSource = world.getChunkManager().getChunkGenerator().getBiomeSource();
if ( lv.size() == 1
&& lv.get(0) instanceof MapValue map
&& biomeSource instanceof MultiNoiseBiomeSource mnbs
) {
Value temperature = map.get(new StringValue("temperature"));
nullCheck(temperature, "temperature");
Value humidity = map.get(new StringValue("humidity"));
nullCheck(humidity, "humidity");
Value continentalness = map.get(new StringValue("continentalness"));
nullCheck(continentalness, "continentalness");
Value erosion = map.get(new StringValue("erosion"));
nullCheck(erosion, "erosion");
Value depth = map.get(new StringValue("depth"));
nullCheck(depth, "depth");
Value weirdness = map.get(new StringValue("weirdness"));
nullCheck(weirdness, "weirdness");
MultiNoiseUtil.NoiseValuePoint point = new MultiNoiseUtil.NoiseValuePoint(
MultiNoiseUtil.method_38665(numberGetOrThrow(temperature)),
MultiNoiseUtil.method_38665(numberGetOrThrow(humidity)),
MultiNoiseUtil.method_38665(numberGetOrThrow(continentalness)),
MultiNoiseUtil.method_38665(numberGetOrThrow(erosion)),
MultiNoiseUtil.method_38665(numberGetOrThrow(depth)),
MultiNoiseUtil.method_38665(numberGetOrThrow(weirdness))
);
biome = mnbs.getBiomeAtPoint(point);
Identifier biomeId = cc.s.getServer().getRegistryManager().get(Registry.BIOME_KEY).getId(biome);
return new StringValue(NBTSerializableValue.nameFromRegistryId(biomeId));
}
BlockArgument locator = BlockArgument.findIn(cc, lv, 0, false, false, true);
if (locator.replacement != null) if (locator.replacement != null)
{ {
biome = world.getRegistryManager().get(Registry.BIOME_KEY).get(InputValidator.identifierOf(locator.replacement)); biome = world.getRegistryManager().get(Registry.BIOME_KEY).get(InputValidator.identifierOf(locator.replacement));
if (biome == null) throw new ThrowStatement(locator.replacement, Throwables.UNKNOWN_BIOME) ; if (biome == null) throw new ThrowStatement(locator.replacement, Throwables.UNKNOWN_BIOME);
} }
else else
{ {
@@ -1156,7 +1212,8 @@ public class WorldAccess {
} }
String biomeFeature = lv.get(locator.offset).getString(); String biomeFeature = lv.get(locator.offset).getString();
BiFunction<ServerWorld, Biome, Value> featureProvider = BiomeInfo.biomeFeatures.get(biomeFeature); BiFunction<ServerWorld, Biome, Value> featureProvider = BiomeInfo.biomeFeatures.get(biomeFeature);
if (featureProvider == null) throw new InternalExpressionException("Unknown biome feature: "+biomeFeature); if (featureProvider == null)
throw new InternalExpressionException("Unknown biome feature: " + biomeFeature);
return featureProvider.apply(world, biome); return featureProvider.apply(world, biome);
}); });
@@ -1512,4 +1569,23 @@ public class WorldAccess {
}); });
} }
@ScarpetFunction(maxParams = -1)
public Value query_noise(Context c, @Locator.Block BlockPos pos, String... noiseQueries) {
int mappedX = BiomeCoords.fromBlock(pos.getX());
int mappedY = BiomeCoords.fromBlock(pos.getY());
int mappedZ = BiomeCoords.fromBlock(pos.getZ());
MultiNoiseUtil.MultiNoiseSampler mns = ((CarpetContext) c).s.getWorld().getChunkManager().getChunkGenerator().getMultiNoiseSampler();
Map<Value, Value> ret = new HashMap<>();
if (noiseQueries.length == 0) {
noiseQueries = new String[]{"continentalness", "erosion", "weirdness", "temperature", "humidity", "depth"};
}
for (String noise : noiseQueries) {
double noiseValue = ((NoiseColumnSamplerInterface) mns).getNoiseSample(noise, mappedX, mappedY, mappedZ);
ret.put(new StringValue(noise), new NumericValue(noiseValue));
}
return MapValue.wrap(ret);
}
} }
+1
View File
@@ -4,3 +4,4 @@ accessible class net/minecraft/server/world/ThreadedAnvilChunkStorage$TicketMana
accessible class net/minecraft/server/world/ServerLightingProvider$Stage accessible class net/minecraft/server/world/ServerLightingProvider$Stage
accessible class net/minecraft/recipe/Ingredient$Entry accessible class net/minecraft/recipe/Ingredient$Entry
accessible class net/minecraft/world/chunk/light/BlockLightStorage$Data accessible class net/minecraft/world/chunk/light/BlockLightStorage$Data
accessible class net/minecraft/world/gen/NoiseColumnSampler$CaveScaler
+2
View File
@@ -204,6 +204,8 @@
"StatePredicate_scarpetMixin", "StatePredicate_scarpetMixin",
"TagPredicate_scarpetMixin", "TagPredicate_scarpetMixin",
"HorseBaseEntity_scarpetMixin", "HorseBaseEntity_scarpetMixin",
"NoiseColumnSamplerMixin_scarpetMixin",
"CaveScalerMixin_scarpetMixin",
"BlockEntity_movableBEMixin", "BlockEntity_movableBEMixin",
"PistonBlock_movableTEMixin", "PistonBlock_movableTEMixin",