From c2cd69f0bd23d4f6a3943c5150e8c6d26c9a4b85 Mon Sep 17 00:00:00 2001 From: Zepalesque <60141811+Zepalesque@users.noreply.github.com> Date: Sun, 23 Jun 2024 10:48:30 -0400 Subject: [PATCH] feat: large rock placer --- gradle.properties | 2 +- .../gen/BlockWithPredicateFeature.java | 13 +- .../world/feature/gen/LargeRockFeature.java | 121 ++++++++++++++++++ .../world/feature/gen/ZenithFeatures.java | 2 +- 4 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 src/main/java/net/zepalesque/zenith/world/feature/gen/LargeRockFeature.java diff --git a/gradle.properties b/gradle.properties index 0062db0..0140992 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false org.gradle.debug=false -mod_version=1.0.82 +mod_version=1.0.83 # Mod mod_id=zenith diff --git a/src/main/java/net/zepalesque/zenith/world/feature/gen/BlockWithPredicateFeature.java b/src/main/java/net/zepalesque/zenith/world/feature/gen/BlockWithPredicateFeature.java index 6fcddd2..f0cd724 100644 --- a/src/main/java/net/zepalesque/zenith/world/feature/gen/BlockWithPredicateFeature.java +++ b/src/main/java/net/zepalesque/zenith/world/feature/gen/BlockWithPredicateFeature.java @@ -45,13 +45,10 @@ public boolean place(FeaturePlaceContext context) { } } - public record Config(BlockStateProvider toPlace, - BlockPredicate predicate) implements FeatureConfiguration { - public static final Codec CODEC = - RecordCodecBuilder.create((config) -> - config.group( - BlockStateProvider.CODEC.fieldOf("to_place").forGetter(Config::toPlace), - BlockPredicate.CODEC.fieldOf("predicate").forGetter(Config::predicate) - ).apply(config, Config::new)); + public record Config(BlockStateProvider toPlace, BlockPredicate predicate) implements FeatureConfiguration { + public static final Codec CODEC = RecordCodecBuilder.create((config) -> config.group( + BlockStateProvider.CODEC.fieldOf("to_place").forGetter(Config::toPlace), + BlockPredicate.CODEC.fieldOf("predicate").forGetter(Config::predicate) + ).apply(config, Config::new)); } } \ No newline at end of file diff --git a/src/main/java/net/zepalesque/zenith/world/feature/gen/LargeRockFeature.java b/src/main/java/net/zepalesque/zenith/world/feature/gen/LargeRockFeature.java new file mode 100644 index 0000000..5814a27 --- /dev/null +++ b/src/main/java/net/zepalesque/zenith/world/feature/gen/LargeRockFeature.java @@ -0,0 +1,121 @@ +package net.zepalesque.zenith.world.feature.gen; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.HolderSet; +import net.minecraft.core.RegistryCodecs; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; +import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; + +public class LargeRockFeature extends Feature { + + public LargeRockFeature(Codec pCodec) { + super(pCodec); + } + + @Override + public boolean place(FeaturePlaceContext context) { + BlockPos origin = context.origin(); + WorldGenLevel level = context.level(); + RandomSource rand = context.random(); + BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); + for (int i = -1; i < 4; i++) { + mutable.setWithOffset(origin, 0, i, 0); + setBlock(mutable, context); + } + Collection placeAbove = new ArrayList<>(); + for (Direction d : Direction.Plane.HORIZONTAL) { + if (rand.nextFloat() < 0.7) { + BlockPos imm = origin.relative(d).relative(d.getCounterClockWise()); + setBlock(imm, context); + for (Direction d1 : Direction.Plane.VERTICAL) { + if (rand.nextFloat() < 0.5) { + mutable.setWithOffset(imm, d1); + setBlock(mutable, context); + if (d1 == Direction.UP) { + placeAbove.add(d); + placeAbove.add(d.getCounterClockWise()); + } + } + } + } + for (int i = -1; i < 3; i++) { + BlockPos imm1 = origin.relative(d); + if (i < 2 || (placeAbove.contains(d) && rand.nextFloat() < 0.7)) { + setBlock(imm1.above(i), context); + } + } + } + if (!placeAbove.isEmpty()) { + int count = placeAbove.size(); + float chance = count == 1 ? 0.3F : count == 2 ? 0.7F : 1; + if (count >= 3 || rand.nextFloat() < chance) { + setBlock(origin.above(5), context); + } + } + + if (rand.nextFloat() < 0.25) { + Direction d1 = Direction.Plane.HORIZONTAL.getRandomDirection(rand); + Direction d2 = rand.nextBoolean() ? d1.getClockWise() : d1.getCounterClockWise(); + BlockPos pos = origin.relative(d1, 2).relative(d2); + BlockPos below = pos.below(); + BlockPos underBelow = below.below(); + if (level.isStateAtPosition(pos, state -> state.isFaceSturdy(level, pos, Direction.UP))) { + placeSecondChunk(pos.above(), mutable, context); + } else if (level.isStateAtPosition(below, state -> state.isFaceSturdy(level, below, Direction.UP))) { + placeSecondChunk(pos, mutable, context); + } else if (level.isStateAtPosition(underBelow, state -> state.isFaceSturdy(level, underBelow, Direction.UP))) { + placeSecondChunk(below, mutable, context); + } + } + return true; + } + + private void placeSecondChunk(BlockPos pos, BlockPos.MutableBlockPos mutable, FeaturePlaceContext context) { + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + int total = Math.abs(x) + Math.abs(y) + Math.abs(z); + boolean place = context.random().nextBoolean() ? total <= 1 : total <= 2; + if (place) { + mutable.setWithOffset(pos, x, y, z); + setBlock(mutable, context); + } + } + } + } + } + + private static void setBlock(BlockPos pos, FeaturePlaceContext context) { + WorldGenLevel level = context.level(); + Config config = context.config(); + BlockStateProvider provider = config.block(); + RandomSource rand = context.random(); + Optional> optional = config.replaceableStates(); + if (level.isStateAtPosition(pos, bs -> bs.isAir() || bs.is(BlockTags.REPLACEABLE) || (optional.isPresent() && bs.is(optional.get())))) { + level.setBlock(pos, provider.getState(rand, pos), 2); + } + } + + public record Config(BlockStateProvider block, Optional> replaceableStates) implements FeatureConfiguration { + public static final Codec CODEC = RecordCodecBuilder.create((config) -> config.group( + BlockStateProvider.CODEC.fieldOf("block").forGetter(Config::block), + RegistryCodecs.homogeneousList(Registries.BLOCK).optionalFieldOf("replaceable_states").forGetter(Config::replaceableStates) + ).apply(config, Config::new)); + } +} diff --git a/src/main/java/net/zepalesque/zenith/world/feature/gen/ZenithFeatures.java b/src/main/java/net/zepalesque/zenith/world/feature/gen/ZenithFeatures.java index 3dc7664..f5ed368 100644 --- a/src/main/java/net/zepalesque/zenith/world/feature/gen/ZenithFeatures.java +++ b/src/main/java/net/zepalesque/zenith/world/feature/gen/ZenithFeatures.java @@ -11,5 +11,5 @@ public class ZenithFeatures { public static DeferredHolder, Feature> BLOCK_WITH_PREDICATE = FEATURES.register("block_with_predicate", () -> new BlockWithPredicateFeature(BlockWithPredicateFeature.Config.CODEC)); public static DeferredHolder, Feature> SURFACE_RULE_LAKE = FEATURES.register("surface_rule_lake", () -> new SurfaceRuleLakeFeature(SurfaceRuleLakeFeature.Config.CODEC)); - + public static DeferredHolder, Feature> LARGE_ROCK = FEATURES.register("large_rock", () -> new LargeRockFeature(LargeRockFeature.Config.CODEC)); }