Refactoring and CrimsonPinewood

This commit is contained in:
Frank 2022-06-05 17:31:03 +02:00
parent 90921451dd
commit 97a65a3707
20 changed files with 626 additions and 182 deletions

View file

@ -15,6 +15,7 @@ import org.betterx.bclib.api.WorldDataAPI;
import org.betterx.bclib.api.dataexchange.DataExchangeAPI;
import org.betterx.bclib.api.dataexchange.handler.autosync.*;
import org.betterx.bclib.api.features.placement.PlacementModifiers;
import org.betterx.bclib.api.surface.rules.Conditions;
import org.betterx.bclib.api.tag.TagAPI;
import org.betterx.bclib.config.Configs;
import org.betterx.bclib.presets.worldgen.BCLWorldPresets;
@ -49,6 +50,7 @@ public class BCLib implements ModInitializer {
DataExchangeAPI.registerMod(MOD_ID);
BCLWorldPresets.registerPresets();
AnvilRecipe.register();
Conditions.registerAll();
DataExchangeAPI.registerDescriptors(List.of(
HelloClient.DESCRIPTOR,

View file

@ -16,6 +16,7 @@ import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.features.config.PlaceFacingBlockConfig;
import org.betterx.bclib.api.features.config.ScatterFeatureConfig;
import org.betterx.bclib.api.features.config.TemplateFeatureConfig;
@ -23,6 +24,9 @@ import java.util.Map.Entry;
import java.util.Optional;
public class BCLFeature {
public static final Feature<PlaceFacingBlockConfig> PLACE_BLOCK = register(
BCLib.makeID("place_block"),
new PlaceBlockFeature<>(PlaceFacingBlockConfig.CODEC));
public static final Feature<ScatterFeatureConfig.OnSolid> SCATTER_ON_SOLID = register(
BCLib.makeID("scatter_on_solid"),
new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC));

View file

@ -297,8 +297,8 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
return modifier(new FindSolidInDirection(dir, distance));
}
public BCLFeatureBuilder findSolidSurface(List<Direction> dir, int distance) {
return modifier(new FindSolidInDirection(dir, distance));
public BCLFeatureBuilder findSolidSurface(List<Direction> dir, int distance, boolean randomSelect) {
return modifier(new FindSolidInDirection(dir, distance, randomSelect));
}
public BCLFeatureBuilder heightmap() {

View file

@ -1,25 +0,0 @@
package org.betterx.bclib.api.features;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import com.mojang.serialization.Codec;
import org.betterx.bclib.api.features.config.BlockPlaceFeatureConfig;
import org.betterx.bclib.util.BlocksHelper;
import java.util.Optional;
public class BlockPlaceFeature<FC extends BlockPlaceFeatureConfig> extends Feature<FC> {
public BlockPlaceFeature(Codec<FC> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<FC> ctx) {
Optional<BlockState> state = ctx.config().getRandomBlock(ctx.random());
if (state.isPresent())
BlocksHelper.setWithoutUpdate(ctx.level(), ctx.origin(), state.get());
return true;
}
}

View file

@ -1,7 +1,10 @@
package org.betterx.bclib.api.features;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
@ -9,7 +12,9 @@ import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConf
import net.minecraft.world.level.levelgen.feature.configurations.RandomPatchConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.SimpleBlockConfiguration;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.RandomizedIntStateProvider;
import org.betterx.bclib.api.features.config.PlaceFacingBlockConfig;
import org.betterx.bclib.api.features.config.ScatterFeatureConfig;
public class FastFeatures {
@ -59,6 +64,24 @@ public class FastFeatures {
new SimpleBlockConfiguration(BlockStateProvider.simple(block)));
}
public static BCLFeature patchWitRandomInt(ResourceLocation location, Block block, IntegerProperty prop) {
return patchWitRandomInt(location, block, prop, 96, 7, 3);
}
public static BCLFeature
patchWitRandomInt(ResourceLocation location,
Block block,
IntegerProperty prop,
int attempts,
int xzSpread,
int ySpread) {
return patch(location,
attempts,
xzSpread,
ySpread,
simple(location, ySpread, false, block.defaultBlockState(), prop));
}
public static BCLFeature
simple(ResourceLocation location,
int searchDist,
@ -67,6 +90,31 @@ public class FastFeatures {
return simple(location, searchDist, rare, feature, NoneFeatureConfiguration.NONE);
}
public static BCLFeature
simple(ResourceLocation location,
int searchDist,
boolean rare,
BlockState baseState,
IntegerProperty property) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (Integer i : property.getPossibleValues()) {
if (i < min) min = i;
if (i > max) max = i;
}
return simple(location,
searchDist,
rare,
Feature.SIMPLE_BLOCK,
new SimpleBlockConfiguration(new RandomizedIntStateProvider(
BlockStateProvider.simple(baseState),
property,
UniformInt.of(min, max)
)));
}
public static <FC extends FeatureConfiguration> BCLFeature
simple(ResourceLocation location,
int searchDist,
@ -104,11 +152,33 @@ public class FastFeatures {
int ySpread,
Feature<FC> feature,
FC config) {
ResourceLocation patchLocation = new ResourceLocation(location.getNamespace(), location.getPath() + "_patch");
final BCLFeature SINGLE = simple(location, ySpread, false, feature, config);
return patch(location, attempts, xzSpread, ySpread, SINGLE);
}
public static BCLFeature
wallPatch(ResourceLocation location,
Block block,
int attempts,
int xzSpread,
int ySpread) {
final BCLFeature SINGLE = simple(location, ySpread, false, BCLFeature.PLACE_BLOCK,
new PlaceFacingBlockConfig(block, PlaceFacingBlockConfig.HORIZONTAL));
return patch(location, attempts, xzSpread, ySpread, SINGLE);
}
public static BCLFeature
patch(ResourceLocation location,
int attempts,
int xzSpread,
int ySpread,
BCLFeature single) {
ResourceLocation patchLocation = new ResourceLocation(location.getNamespace(), location.getPath() + "_patch");
return BCLFeatureBuilder
.start(patchLocation, Feature.RANDOM_PATCH)
.buildAndRegister(new RandomPatchConfiguration(attempts, xzSpread, ySpread, SINGLE.getPlacedFeature()));
.buildAndRegister(new RandomPatchConfiguration(attempts, xzSpread, ySpread, single.getPlacedFeature()));
}
}

View file

@ -0,0 +1,18 @@
package org.betterx.bclib.api.features;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import com.mojang.serialization.Codec;
import org.betterx.bclib.api.features.config.PlaceBlockFeatureConfig;
public class PlaceBlockFeature<FC extends PlaceBlockFeatureConfig> extends Feature<FC> {
public PlaceBlockFeature(Codec<FC> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<FC> ctx) {
return ctx.config().place(ctx);
}
}

View file

@ -1,59 +0,0 @@
package org.betterx.bclib.api.features.config;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import java.util.List;
import java.util.Optional;
public class BlockPlaceFeatureConfig implements FeatureConfiguration {
public static final Codec<BlockPlaceFeatureConfig> CODEC = SimpleWeightedRandomList
.wrappedCodec(BlockState.CODEC)
.comapFlatMap(BlockPlaceFeatureConfig::create, cfg -> cfg.weightedList)
.fieldOf("entries").codec();
private final SimpleWeightedRandomList<BlockState> weightedList;
private static DataResult<BlockPlaceFeatureConfig> create(SimpleWeightedRandomList<BlockState> simpleWeightedRandomList) {
if (simpleWeightedRandomList.isEmpty()) {
return DataResult.error("BlockPlaceFeatureConfig with no states");
}
return DataResult.success(new BlockPlaceFeatureConfig(simpleWeightedRandomList));
}
private static SimpleWeightedRandomList<BlockState> convert(List<BlockState> states) {
var builder = SimpleWeightedRandomList.<BlockState>builder();
for (BlockState s : states) builder.add(s, 1);
return builder.build();
}
public BlockPlaceFeatureConfig(Block block) {
this(block.defaultBlockState());
}
public BlockPlaceFeatureConfig(BlockState state) {
this(SimpleWeightedRandomList
.<BlockState>builder()
.add(state, 1)
.build());
}
public BlockPlaceFeatureConfig(List<BlockState> states) {
this(convert(states));
}
public BlockPlaceFeatureConfig(SimpleWeightedRandomList<BlockState> blocks) {
this.weightedList = blocks;
}
public Optional<BlockState> getRandomBlock(RandomSource random) {
return this.weightedList.getRandomValue(random);
}
}

View file

@ -0,0 +1,76 @@
package org.betterx.bclib.api.features.config;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.List;
import java.util.Optional;
public abstract class PlaceBlockFeatureConfig implements FeatureConfiguration {
protected static <T extends PlaceBlockFeatureConfig> RecordCodecBuilder<T, SimpleWeightedRandomList<BlockState>> blockStateCodec() {
return SimpleWeightedRandomList
.wrappedCodec(BlockState.CODEC)
.fieldOf("entries")
.forGetter((T o) -> o.weightedList);
}
protected final SimpleWeightedRandomList<BlockState> weightedList;
protected static SimpleWeightedRandomList<BlockState> buildWeightedList(List<BlockState> states) {
var builder = SimpleWeightedRandomList.<BlockState>builder();
for (BlockState s : states) builder.add(s, 1);
return builder.build();
}
protected static SimpleWeightedRandomList<BlockState> buildWeightedList(BlockState state) {
return SimpleWeightedRandomList
.<BlockState>builder()
.add(state, 1)
.build();
}
public PlaceBlockFeatureConfig(Block block) {
this(block.defaultBlockState());
}
public PlaceBlockFeatureConfig(BlockState state) {
this(buildWeightedList(state));
}
public PlaceBlockFeatureConfig(List<BlockState> states) {
this(buildWeightedList(states));
}
public PlaceBlockFeatureConfig(SimpleWeightedRandomList<BlockState> blocks) {
this.weightedList = blocks;
}
public Optional<BlockState> getRandomBlock(RandomSource random) {
return this.weightedList.getRandomValue(random);
}
public boolean place(FeaturePlaceContext<? extends PlaceBlockFeatureConfig> ctx) {
Optional<BlockState> state = getRandomBlock(ctx.random());
if (state.isPresent()) {
return placeBlock(ctx, ctx.level(), ctx.origin(), state.get());
}
return false;
}
protected abstract boolean placeBlock(FeaturePlaceContext<? extends PlaceBlockFeatureConfig> ctx,
WorldGenLevel level,
BlockPos pos,
BlockState targetState);
}

View file

@ -0,0 +1,77 @@
package org.betterx.bclib.api.features.config;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.random.SimpleWeightedRandomList;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.betterx.bclib.util.BlocksHelper;
import java.util.List;
public class PlaceFacingBlockConfig extends PlaceBlockFeatureConfig {
public static final Codec<PlaceFacingBlockConfig> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
blockStateCodec(),
ExtraCodecs.nonEmptyList(Direction.CODEC.listOf())
.fieldOf("dir")
.orElse(List.of(Direction.NORTH))
.forGetter(a -> a.directions)
).apply(instance, PlaceFacingBlockConfig::new)
);
public static final List<Direction> HORIZONTAL = List.of(Direction.NORTH,
Direction.EAST,
Direction.WEST,
Direction.SOUTH);
public static final List<Direction> VERTICAL = List.of(Direction.UP, Direction.DOWN);
public static final List<Direction> ALL = List.of(Direction.NORTH,
Direction.EAST,
Direction.SOUTH,
Direction.WEST,
Direction.UP,
Direction.DOWN);
private final List<Direction> directions;
public PlaceFacingBlockConfig(Block block, List<Direction> dir) {
this(block.defaultBlockState(), dir);
}
public PlaceFacingBlockConfig(BlockState state, List<Direction> dir) {
this(buildWeightedList(state), dir);
}
public PlaceFacingBlockConfig(List<BlockState> states, List<Direction> dir) {
this(buildWeightedList(states), dir);
}
public PlaceFacingBlockConfig(SimpleWeightedRandomList<BlockState> blocks, List<Direction> dir) {
super(blocks);
directions = dir;
}
@Override
public boolean placeBlock(FeaturePlaceContext<? extends PlaceBlockFeatureConfig> ctx,
WorldGenLevel level,
BlockPos pos,
BlockState targetState) {
BlockState lookupState;
for (Direction dir : directions) {
lookupState = targetState.setValue(HorizontalDirectionalBlock.FACING, dir);
if (lookupState.canSurvive(level, pos)) {
BlocksHelper.setWithoutUpdate(level, pos, lookupState);
return true;
}
}
return false;
}
}

View file

@ -4,6 +4,8 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.RandomSource;
import net.minecraft.util.valueproviders.IntProvider;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.level.levelgen.placement.PlacementContext;
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
@ -23,7 +25,9 @@ public class FindSolidInDirection extends PlacementModifier {
.fieldOf("dir")
.orElse(List.of(Direction.DOWN))
.forGetter(a -> a.direction),
Codec.intRange(1, 32).fieldOf("dist").orElse(12).forGetter((p) -> p.maxSearchDistance))
Codec.intRange(1, 32).fieldOf("dist").orElse(12).forGetter((p) -> p.maxSearchDistance),
Codec.BOOL.fieldOf("random:select").orElse(true).forGetter(p -> p.randomSelect)
)
.apply(instance,
FindSolidInDirection::new));
protected static final FindSolidInDirection DOWN = new FindSolidInDirection(Direction.DOWN, 6);
@ -31,13 +35,23 @@ public class FindSolidInDirection extends PlacementModifier {
private final List<Direction> direction;
private final int maxSearchDistance;
private final boolean randomSelect;
private final IntProvider provider;
public FindSolidInDirection(Direction direction, int maxSearchDistance) {
this(List.of(direction), maxSearchDistance);
this(List.of(direction), maxSearchDistance, false);
}
public FindSolidInDirection(List<Direction> direction, int maxSearchDistance) {
this(direction, maxSearchDistance, direction.size() > 1);
}
public FindSolidInDirection(List<Direction> direction, int maxSearchDistance, boolean randomSelect) {
this.direction = direction;
this.maxSearchDistance = maxSearchDistance;
this.provider = UniformInt.of(0, direction.size() - 1);
this.randomSelect = randomSelect;
}
public static PlacementModifier down() {
@ -59,24 +73,37 @@ public class FindSolidInDirection extends PlacementModifier {
}
public Direction randomDirection(RandomSource random) {
return direction.get(Math.max(0, Math.min(direction.size(), random.nextInt(direction.size()))));
return direction.get(provider.sample(random));
}
@Override
public Stream<BlockPos> getPositions(PlacementContext placementContext,
RandomSource randomSource,
BlockPos blockPos) {
var builder = Stream.<BlockPos>builder();
if (randomSelect) {
submitSingle(placementContext, blockPos, builder, randomDirection(randomSource));
} else {
for (Direction d : direction) {
submitSingle(placementContext, blockPos, builder, d);
}
}
return builder.build();
}
private void submitSingle(PlacementContext placementContext,
BlockPos blockPos,
Stream.Builder<BlockPos> builder,
Direction d) {
BlockPos.MutableBlockPos POS = blockPos.mutable();
Direction d = randomDirection(randomSource);
if (BlocksHelper.findOnSurroundingSurface(placementContext.getLevel(),
POS,
d,
maxSearchDistance,
BlocksHelper::isTerrain)) {
return Stream.of(POS);
builder.add(POS);
}
return Stream.of();
}
@Override

View file

@ -10,8 +10,9 @@ import net.minecraft.world.level.levelgen.placement.CaveSurface;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.betterx.bclib.api.biomes.BiomeAPI;
import org.betterx.bclib.api.surface.rules.Conditions;
import org.betterx.bclib.api.surface.rules.DoubleBlockSurfaceNoiseCondition;
import org.betterx.bclib.api.surface.rules.NoiseCondition;
import org.betterx.bclib.world.surface.DoubleBlockSurfaceNoiseCondition;
import java.util.Collections;
import java.util.List;
@ -237,7 +238,7 @@ public class SurfaceRuleBuilder {
* @return same {@link SurfaceRuleBuilder} instance.
*/
public SurfaceRuleBuilder chancedFloor(BlockState surfaceBlockA, BlockState surfaceBlockB) {
return chancedFloor(surfaceBlockA, surfaceBlockB, DoubleBlockSurfaceNoiseCondition.CONDITION);
return chancedFloor(surfaceBlockA, surfaceBlockB, Conditions.DOUBLE_BLOCK_SURFACE_NOISE);
}
/**
@ -267,6 +268,25 @@ public class SurfaceRuleBuilder {
return this;
}
public SurfaceRuleBuilder chancedFloor(BlockState surfaceBlockA, RuleSource surfaceBlockB, NoiseCondition noise) {
entryInstance = getFromCache("chancedFloor_" + surfaceBlockA + "_" + surfaceBlockB + "_" + noise.getClass()
.getSimpleName(),
() -> {
RuleSource rule =
SurfaceRules.ifTrue(SurfaceRules.ON_FLOOR,
SurfaceRules.sequence(
SurfaceRules.ifTrue(noise,
SurfaceRules.state(
surfaceBlockA)),
surfaceBlockB
)
);
return new SurfaceRuleEntry(4, rule);
});
rules.add(entryInstance);
return this;
}
/**
* Finalise rule building process.
*

View file

@ -0,0 +1,60 @@
package org.betterx.bclib.api.surface.rules;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.valueproviders.UniformFloat;
import net.minecraft.world.level.levelgen.SurfaceRules;
import com.mojang.serialization.Codec;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.interfaces.NumericProvider;
public class Conditions {
public static final ThresholdCondition DOUBLE_BLOCK_SURFACE_NOISE = new ThresholdCondition(4141,
0,
UniformFloat.of(-0.4f, 0.4f),
0.1,
0.1);
public static final ThresholdCondition FORREST_FLOOR_SURFACE_NOISE_A = new ThresholdCondition(614,
0,
UniformFloat.of(-0.2f, 0f),
0.1,
0.1);
public static final ThresholdCondition FORREST_FLOOR_SURFACE_NOISE_B = new ThresholdCondition(614,
0,
UniformFloat.of(-0.7f, -0.5f),
0.1,
0.1);
public static final ThresholdCondition NETHER_SURFACE_NOISE = new ThresholdCondition(245,
0,
UniformFloat.of(-0.7f, -0.5f),
0.05,
0.05);
public static final VolumeThresholdCondition NETHER_VOLUME_NOISE = new VolumeThresholdCondition(245,
0,
UniformFloat.of(-0.1f, 0.2f),
0.1,
0.2,
0.1);
public static final NumericProvider NETHER_NOISE = new NetherNoiseCondition();
public static void register(ResourceLocation location, Codec<? extends SurfaceRules.ConditionSource> codec) {
Registry.register(Registry.CONDITION, location, codec);
}
public static void registerNumeric(ResourceLocation location, Codec<? extends NumericProvider> codec) {
Registry.register(NumericProvider.NUMERIC_PROVIDER, location, codec);
}
public static void registerAll() {
registerNumeric(BCLib.makeID("rnd_int"), RandomIntProvider.CODEC);
registerNumeric(BCLib.makeID("nether_noise"), NetherNoiseCondition.CODEC);
register(BCLib.makeID("threshold_condition"), ThresholdCondition.CODEC);
register(BCLib.makeID("volume_threshold_condition"), VolumeThresholdCondition.CODEC);
}
}

View file

@ -0,0 +1,5 @@
package org.betterx.bclib.api.surface.rules;
public class DoubleBlockSurfaceNoiseCondition {
public static final ThresholdCondition CONDITION = Conditions.DOUBLE_BLOCK_SURFACE_NOISE;
}

View file

@ -0,0 +1,43 @@
package org.betterx.bclib.api.surface.rules;
import com.mojang.serialization.Codec;
import org.betterx.bclib.interfaces.NumericProvider;
import org.betterx.bclib.mixin.common.SurfaceRulesContextAccessor;
import org.betterx.bclib.util.MHelper;
public class NetherNoiseCondition implements NumericProvider {
public static final Codec<NetherNoiseCondition> CODEC = Codec.BYTE.fieldOf("nether_noise")
.xmap((obj) -> (NetherNoiseCondition) Conditions.NETHER_NOISE,
obj -> (byte) 0)
.codec();
NetherNoiseCondition() {
}
@Override
public Codec<? extends NumericProvider> pcodec() {
return CODEC;
}
@Override
public int getNumber(SurfaceRulesContextAccessor context) {
final int x = context.getBlockX();
final int y = context.getBlockY();
final int z = context.getBlockZ();
double value = Conditions.NETHER_VOLUME_NOISE.noiseContext.noise.eval(x * Conditions.NETHER_VOLUME_NOISE.scaleX,
y * Conditions.NETHER_VOLUME_NOISE.scaleY,
z * Conditions.NETHER_VOLUME_NOISE.scaleZ);
int offset = Conditions.NETHER_VOLUME_NOISE.noiseContext.random.nextInt(20) == 0 ? 3 : 0;
float cmp = MHelper.randRange(0.4F, 0.5F, Conditions.NETHER_VOLUME_NOISE.noiseContext.random);
if (value > cmp || value < -cmp) return 2 + offset;
if (value > Conditions.NETHER_VOLUME_NOISE.range.sample(Conditions.NETHER_VOLUME_NOISE.noiseContext.random))
return 0 + offset;
return 1 + offset;
}
}

View file

@ -1,9 +1,6 @@
package org.betterx.bclib.api.surface.rules;
import net.minecraft.core.Registry;
import com.mojang.serialization.Codec;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.interfaces.NumericProvider;
import org.betterx.bclib.mixin.common.SurfaceRulesContextAccessor;
import org.betterx.bclib.util.MHelper;
@ -24,6 +21,6 @@ public record RandomIntProvider(int range) implements NumericProvider {
}
static {
Registry.register(NumericProvider.NUMERIC_PROVIDER, BCLib.makeID("rnd_int"), RandomIntProvider.CODEC);
}
}

View file

@ -28,4 +28,6 @@ public abstract class SurfaceNoiseCondition implements NoiseCondition {
}
public abstract boolean test(SurfaceRulesContextAccessor context);
}

View file

@ -0,0 +1,79 @@
package org.betterx.bclib.api.surface.rules;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.util.RandomSource;
import net.minecraft.util.valueproviders.ConstantFloat;
import net.minecraft.util.valueproviders.FloatProvider;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
import net.minecraft.world.level.levelgen.SurfaceRules;
import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.betterx.bclib.mixin.common.SurfaceRulesContextAccessor;
import org.betterx.bclib.noise.OpenSimplexNoise;
import java.util.Map;
public class ThresholdCondition extends SurfaceNoiseCondition {
private static final Map<Long, Context> NOISES = Maps.newHashMap();
public static final Codec<ThresholdCondition> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.LONG.fieldOf("seed").forGetter(p -> p.noiseContext.seed),
Codec.DOUBLE.fieldOf("threshold").orElse(0.0).forGetter(p -> p.threshold),
FloatProvider.CODEC.fieldOf("threshold_offset").orElse(ConstantFloat.of(0)).forGetter(p -> p.range),
Codec.DOUBLE.fieldOf("scale_x").orElse(0.1).forGetter(p -> p.scaleX),
Codec.DOUBLE.fieldOf("scale_z").orElse(0.1).forGetter(p -> p.scaleZ)
)
.apply(instance, ThresholdCondition::new));
public static final KeyDispatchDataCodec<ThresholdCondition> KEY_CODEC = KeyDispatchDataCodec.of(CODEC);
private final Context noiseContext;
private final double threshold;
private final FloatProvider range;
private final double scaleX;
private final double scaleZ;
public ThresholdCondition(long noiseSeed, double threshold, FloatProvider range, double scaleX, double scaleZ) {
this.threshold = threshold;
this.range = range;
this.scaleX = scaleX;
this.scaleZ = scaleZ;
noiseContext = NOISES.computeIfAbsent(noiseSeed, seed -> new Context(seed));
}
@Override
public boolean test(SurfaceRulesContextAccessor context) {
final double x = context.getBlockX() * scaleX;
final double z = context.getBlockZ() * scaleZ;
if (noiseContext.lastX == x && noiseContext.lastZ == z)
return noiseContext.lastValue + range.sample(noiseContext.random) > threshold;
double value = noiseContext.noise.eval(x, z);
noiseContext.lastX = x;
noiseContext.lastZ = z;
noiseContext.lastValue = value;
return value + range.sample(noiseContext.random) > threshold;
}
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return KEY_CODEC;
}
static class Context {
public final OpenSimplexNoise noise;
public final RandomSource random;
public final long seed;
public double lastX = Integer.MIN_VALUE;
public double lastZ = Integer.MIN_VALUE;
public double lastValue = 0;
Context(long seed) {
this.seed = seed;
this.noise = new OpenSimplexNoise(seed);
this.random = new LegacyRandomSource(seed * 2);
}
}
}

View file

@ -0,0 +1,103 @@
package org.betterx.bclib.api.surface.rules;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.util.RandomSource;
import net.minecraft.util.valueproviders.ConstantFloat;
import net.minecraft.util.valueproviders.FloatProvider;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
import net.minecraft.world.level.levelgen.SurfaceRules;
import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.betterx.bclib.mixin.common.SurfaceRulesContextAccessor;
import org.betterx.bclib.noise.OpenSimplexNoise;
import java.util.Map;
public class VolumeThresholdCondition extends VolumeNoiseCondition {
private static final Map<Long, VolumeThresholdCondition.Context> NOISES = Maps.newHashMap();
public static final Codec<VolumeThresholdCondition> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.LONG.fieldOf("seed").forGetter(p -> p.noiseContext.seed),
Codec.DOUBLE.fieldOf("threshold").orElse(0.0).forGetter(p -> p.threshold),
FloatProvider.CODEC.fieldOf("threshold_offset").orElse(ConstantFloat.of(0)).forGetter(p -> p.range),
Codec.DOUBLE.fieldOf("scale_x").orElse(0.1).forGetter(p -> p.scaleX),
Codec.DOUBLE.fieldOf("scale_y").orElse(0.1).forGetter(p -> p.scaleY),
Codec.DOUBLE.fieldOf("scale_z").orElse(0.1).forGetter(p -> p.scaleZ)
)
.apply(instance, VolumeThresholdCondition::new));
public static final KeyDispatchDataCodec<VolumeThresholdCondition> KEY_CODEC = KeyDispatchDataCodec.of(CODEC);
public final VolumeThresholdCondition.Context noiseContext;
public final double threshold;
public final FloatProvider range;
public final double scaleX;
public final double scaleY;
public final double scaleZ;
public VolumeThresholdCondition(long noiseSeed,
double threshold,
FloatProvider range,
double scaleX,
double scaleY,
double scaleZ) {
this.threshold = threshold;
this.range = range;
this.scaleX = scaleX;
this.scaleY = scaleY;
this.scaleZ = scaleZ;
noiseContext = NOISES.computeIfAbsent(noiseSeed, seed -> new Context(seed));
}
public double getValue(SurfaceRulesContextAccessor context) {
return getValue(context.getBlockX(), context.getBlockY(), context.getBlockZ());
}
public double getValue(int xx, int yy, int zz) {
final double x = xx * scaleX;
final double y = yy * scaleY;
final double z = zz * scaleZ;
if (noiseContext.lastX == x
&& noiseContext.lastY == y
&& noiseContext.lastZ == z)
return noiseContext.lastValue + range.sample(noiseContext.random);
double value = noiseContext.noise.eval(x, y, z);
noiseContext.lastX = x;
noiseContext.lastZ = z;
noiseContext.lastY = y;
noiseContext.lastValue = value;
return value + range.sample(noiseContext.random);
}
@Override
public boolean test(SurfaceRulesContextAccessor context) {
return getValue(context) > threshold;
}
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return KEY_CODEC;
}
public static class Context {
public final OpenSimplexNoise noise;
public final RandomSource random;
public final long seed;
double lastX = Integer.MIN_VALUE;
double lastY = Integer.MIN_VALUE;
double lastZ = Integer.MIN_VALUE;
double lastValue = 0;
Context(long seed) {
this.seed = seed;
this.noise = new OpenSimplexNoise(seed);
this.random = new LegacyRandomSource(seed * 3 + 1);
}
}
}

View file

@ -3,6 +3,7 @@ package org.betterx.bclib.api.tag;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
public class NamedBlockTags {
@ -36,4 +37,8 @@ public class NamedBlockTags {
public static final TagKey<Block> SOUL_SPEED_BLOCKS = BlockTags.SOUL_SPEED_BLOCKS;
public static final TagKey<Block> BEACON_BASE_BLOCKS = BlockTags.BEACON_BASE_BLOCKS;
public static final TagKey<Block> STONE_BRICKS = BlockTags.STONE_BRICKS;
static {
TagAPI.BLOCKS.add(BlockTags.NETHER_CARVER_REPLACEABLES, Blocks.RED_SAND, Blocks.MAGMA_BLOCK);
}
}

View file

@ -1,60 +0,0 @@
package org.betterx.bclib.world.surface;
import net.minecraft.core.Registry;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.world.level.levelgen.SurfaceRules;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.surface.rules.SurfaceNoiseCondition;
import org.betterx.bclib.mixin.common.SurfaceRulesContextAccessor;
import org.betterx.bclib.noise.OpenSimplexNoise;
import org.betterx.bclib.util.MHelper;
public class DoubleBlockSurfaceNoiseCondition extends SurfaceNoiseCondition {
public static final DoubleBlockSurfaceNoiseCondition CONDITION = new DoubleBlockSurfaceNoiseCondition(0);
private static final OpenSimplexNoise NOISE = new OpenSimplexNoise(4141);
public static final Codec<DoubleBlockSurfaceNoiseCondition> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.DOUBLE.fieldOf("threshold").orElse(0.0).forGetter(o -> o.threshold)
)
.apply(instance, DoubleBlockSurfaceNoiseCondition::new));
public static final KeyDispatchDataCodec<DoubleBlockSurfaceNoiseCondition> KEY_CODEC = KeyDispatchDataCodec.of(
CODEC);
private final double threshold;
public DoubleBlockSurfaceNoiseCondition(double threshold) {
this.threshold = threshold;
}
@Override
public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
return KEY_CODEC;
}
private static int lastX = Integer.MIN_VALUE;
private static int lastZ = Integer.MIN_VALUE;
private static double lastValue = 0;
@Override
public boolean test(SurfaceRulesContextAccessor context) {
final int x = context.getBlockX();
final int z = context.getBlockZ();
if (lastX == x && lastZ == z) return lastValue > threshold;
double value = NOISE.eval(x * 0.1, z * 0.1) + MHelper.randRange(-0.4, 0.4, MHelper.RANDOM_SOURCE);
lastX = x;
lastZ = z;
lastValue = value;
return value > threshold;
}
static {
Registry.register(Registry.CONDITION,
BCLib.makeID("doubleblock_surface"),
DoubleBlockSurfaceNoiseCondition.CODEC);
}
}