From 5faf0ef1348472a69ce0d1903cb2a9dc8cbca304 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 15 Nov 2022 16:30:34 +0100 Subject: [PATCH] More updates to new BoneMealAPI --- src/main/java/org/betterx/bclib/BCLib.java | 2 + .../org/betterx/bclib/api/v2/BonemealAPI.java | 19 +++ .../bclib/api/v3/bonemeal/BlockSpreader.java | 76 +++++++++ .../bclib/api/v3/bonemeal/BonemealAPI.java | 144 ++++++++++++++++++ ...reader.java => BonemealBlockSpreader.java} | 2 +- .../api/v3/bonemeal/BonemealGrassLike.java | 16 +- .../api/v3/bonemeal/BonemealNyliumLike.java | 22 +-- .../api/v3/bonemeal/EndStoneSpreader.java | 29 +--- .../api/v3/bonemeal/FeatureSpreader.java | 40 +++++ .../api/v3/bonemeal/NetherrackSpreader.java | 75 +-------- .../bonemeal/TaggedBonemealBlockSpreader.java | 23 +++ .../features/BCLConfigureFeature.java | 29 ++-- .../levelgen/features/BCLFeatureBuilder.java | 11 +- .../features/CommonPlacedFeatureBuilder.java | 7 + .../bclib/api/v3/tag/BCLBlockTags.java | 31 ++++ .../bclib/mixin/common/BoneMealItemMixin.java | 31 +--- .../together/tag/v3/CommonBlockTags.java | 5 - .../worlds/together/tag/v3/TagRegistry.java | 4 + 18 files changed, 411 insertions(+), 155 deletions(-) create mode 100644 src/main/java/org/betterx/bclib/api/v3/bonemeal/BlockSpreader.java create mode 100644 src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealAPI.java rename src/main/java/org/betterx/bclib/api/v3/bonemeal/{BonemealSpreader.java => BonemealBlockSpreader.java} (93%) create mode 100644 src/main/java/org/betterx/bclib/api/v3/bonemeal/FeatureSpreader.java create mode 100644 src/main/java/org/betterx/bclib/api/v3/bonemeal/TaggedBonemealBlockSpreader.java create mode 100644 src/main/java/org/betterx/bclib/api/v3/tag/BCLBlockTags.java diff --git a/src/main/java/org/betterx/bclib/BCLib.java b/src/main/java/org/betterx/bclib/BCLib.java index de1bf196..50d2c4d7 100644 --- a/src/main/java/org/betterx/bclib/BCLib.java +++ b/src/main/java/org/betterx/bclib/BCLib.java @@ -15,6 +15,7 @@ import org.betterx.bclib.api.v2.levelgen.surface.rules.Conditions; import org.betterx.bclib.api.v2.poi.PoiManager; import org.betterx.bclib.api.v3.levelgen.features.blockpredicates.BlockPredicates; import org.betterx.bclib.api.v3.levelgen.features.placement.PlacementModifiers; +import org.betterx.bclib.api.v3.tag.BCLBlockTags; import org.betterx.bclib.commands.CommandRegistry; import org.betterx.bclib.config.Configs; import org.betterx.bclib.networking.VersionChecker; @@ -61,6 +62,7 @@ public class BCLib implements ModInitializer { AnvilRecipe.register(); Conditions.registerAll(); CommandRegistry.register(); + BCLBlockTags.ensureStaticallyLoaded(); PoiManager.registerAll(); DataExchangeAPI.registerDescriptors(List.of( diff --git a/src/main/java/org/betterx/bclib/api/v2/BonemealAPI.java b/src/main/java/org/betterx/bclib/api/v2/BonemealAPI.java index 3a18607c..e8470752 100644 --- a/src/main/java/org/betterx/bclib/api/v2/BonemealAPI.java +++ b/src/main/java/org/betterx/bclib/api/v2/BonemealAPI.java @@ -25,6 +25,7 @@ public class BonemealAPI { private static final Set TERRAIN_TO_SPREAD = Sets.newHashSet(); private static final Set TERRAIN = Sets.newHashSet(); + @Deprecated(forRemoval = true) public static void addSpreadableBlock(Block spreadableBlock, Block surfaceForSpread) { SPREADABLE_BLOCKS.put(spreadableBlock, surfaceForSpread); TERRAIN_TO_SPREAD.add(surfaceForSpread); @@ -35,38 +36,53 @@ public class BonemealAPI { return TERRAIN.contains(block); } + @Deprecated(forRemoval = true) public static boolean isSpreadableTerrain(Block block) { return TERRAIN_TO_SPREAD.contains(block); } + @Deprecated(forRemoval = true) public static Block getSpreadable(Block block) { return SPREADABLE_BLOCKS.get(block); } + @Deprecated(forRemoval = true) public static void addLandGrass(Block plant, Block... terrain) { addLandGrass(makeConsumer(plant), terrain); } + @Deprecated(forRemoval = true) public static void addLandGrass(BiConsumer plant, Block... terrain) { for (Block block : terrain) { addLandGrass(plant, block, 1F); } } + /** + * This API is deprecated, please use the new {@link org.betterx.bclib.api.v3.bonemeal.BonemealAPI}. + * + * @param biome + * @param plant + * @param terrain + */ + @Deprecated(forRemoval = true) public static void addLandGrass(ResourceLocation biome, Block plant, Block... terrain) { addLandGrass(biome, makeConsumer(plant), terrain); } + @Deprecated(forRemoval = true) public static void addLandGrass(ResourceLocation biome, BiConsumer plant, Block... terrain) { for (Block block : terrain) { addLandGrass(biome, plant, block, 1F); } } + @Deprecated(forRemoval = true) public static void addLandGrass(Block plant, Block terrain, float chance) { addLandGrass(makeConsumer(plant), terrain, chance); } + @Deprecated(forRemoval = true) public static void addLandGrass(BiConsumer plant, Block terrain, float chance) { WeightedList> list = LAND_GRASS_TYPES.get(terrain); if (list == null) { @@ -77,10 +93,12 @@ public class BonemealAPI { list.add(plant, chance); } + @Deprecated(forRemoval = true) public static void addLandGrass(ResourceLocation biome, Block plant, Block terrain, float chance) { addLandGrass(biome, makeConsumer(plant), terrain, chance); } + @Deprecated(forRemoval = true) public static void addLandGrass( ResourceLocation biome, BiConsumer plant, @@ -159,6 +177,7 @@ public class BonemealAPI { list.add(plant, chance); } + @Deprecated(forRemoval = true) public static BiConsumer getLandGrass( ResourceLocation biomeID, Block terrain, diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BlockSpreader.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BlockSpreader.java new file mode 100644 index 00000000..11609628 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BlockSpreader.java @@ -0,0 +1,76 @@ +package org.betterx.bclib.api.v3.bonemeal; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.util.random.SimpleWeightedRandomList; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider; + +import java.util.HashMap; +import java.util.Map; + +abstract class BlockSpreader implements BonemealBlockSpreader { + protected abstract boolean isValidSource(BlockState state); + protected abstract boolean hasCustomBehaviour(BlockState state); + + public boolean isValidBonemealSpreadTarget( + BlockGetter blockGetter, + BlockPos blockPos, + BlockState blockState, + boolean bl + ) { + if (!blockGetter.getBlockState(blockPos.above()).propagatesSkylightDown(blockGetter, blockPos)) { + return false; + } else { + for (BlockPos testPos : BlockPos.betweenClosed( + blockPos.offset(-1, -1, -1), + blockPos.offset(1, 1, 1) + )) { + BlockState state = blockGetter.getBlockState(testPos); + if (isValidSource(state)) + if (hasCustomBehaviour(state)) + return true; + } + return false; + } + } + + public boolean performBonemealSpread( + ServerLevel serverLevel, + RandomSource randomSource, + BlockPos blockPos, + BlockState blockState + ) { + final Map sourceBlocks = new HashMap<>(); + + for (BlockPos testPos : BlockPos.betweenClosed( + blockPos.offset(-1, -1, -1), + blockPos.offset(1, 1, 1) + )) { + BlockState state = serverLevel.getBlockState(testPos); + if (isValidSource(state)) { + sourceBlocks.compute(state, (k, v) -> { + if (v == null) return 1; + return v + 1; + }); + } + } + + SimpleWeightedRandomList.Builder builder = new SimpleWeightedRandomList.Builder<>(); + for (Map.Entry e : sourceBlocks.entrySet()) { + builder.add(e.getKey(), e.getValue()); + } + WeightedStateProvider provider = new WeightedStateProvider(builder.build()); + + BlockState bl = provider.getState(randomSource, blockPos); + if (bl != null) { + serverLevel.setBlock(blockPos, bl, 3); + return true; + } + + + return false; + } +} diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealAPI.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealAPI.java new file mode 100644 index 00000000..ea7aac89 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealAPI.java @@ -0,0 +1,144 @@ +package org.betterx.bclib.api.v3.bonemeal; + +import org.betterx.bclib.api.v3.levelgen.features.BCLConfigureFeature; +import org.betterx.bclib.api.v3.tag.BCLBlockTags; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.Feature; + +import java.util.HashMap; +import java.util.Map; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +public class BonemealAPI { + public static BonemealAPI INSTANCE = new BonemealAPI(); + private final Map, BonemealBlockSpreader> taggedSpreaders; + private final Map featureSpreaders; + + private BonemealAPI() { + taggedSpreaders = new HashMap<>(); + featureSpreaders = new HashMap<>(); + + addSpreadableBlocks(BCLBlockTags.BONEMEAL_TARGET_NETHERRACK, NetherrackSpreader.INSTANCE); + addSpreadableBlocks(BCLBlockTags.BONEMEAL_TARGET_END_STONE, EndStoneSpreader.INSTANCE); + } + + /** + * Bonemeal can be used to spread vegetation to neighbouring blocks. + *

+ * This method allows you to register a block (the type that was clicked with bonemeal) with + * a {@link BCLConfigureFeature} that will be placed on the bonemeald block + *

+ * You can achieve the same behaviour by implementing {@link BonemealNyliumLike} on your custom + * BlockClass. This is mainly intended for vanilla Blocks where you need to add bonemeal + * behaviour + * + * @param target The block-type + * @param spreadableFeature the feature to place + */ + public void addSpreadableFeatures( + Block target, + @NotNull BCLConfigureFeature, ?> spreadableFeature + ) { + featureSpreaders.put(target, new FeatureSpreader(target, spreadableFeature)); + } + + /** + * Bonemeal can be used to spread for example Nylium to Netherrack. + *

+ * In this example, Netherrack is the target block which will get replaced by one of the source blocks (like + * Warped or Crimson Nylium. You can register Tag-Combinations to easily add your own behaviour for custom + * blocks. + *

+ * When a Block with the Target-Tag + * + * @param targetTag If you click a Block with the given Tag using Bonemeal, you will replace it with + * a block from the sourceTag + * @param sourceTag Blocks with this Tag can replace the Target block if they are in a 3x3 Neighborhood + * centered around the target Block. + */ + public void addSpreadableBlocks(@NotNull TagKey targetTag, @NotNull TagKey sourceTag) { + taggedSpreaders.put(targetTag, new TaggedBonemealBlockSpreader(sourceTag)); + } + + /** + * See {@link #addSpreadableBlocks(TagKey, TagKey)} for Details. + * + * @param targetTag If you click a Block with the given Tag using Bonemeal, you will replace it with + * * a block from the sourceTag + * @param spreader The {@link BonemealBlockSpreader}-Object that is called when a corresponding target-Block + * is clicked with Bone-Meal + */ + public void addSpreadableBlocks(@NotNull TagKey targetTag, @NotNull BonemealBlockSpreader spreader) { + taggedSpreaders.put(targetTag, spreader); + } + + /** + * When a block is clicked with Bonemeal, this method will be called with the state of the given Block. + *

+ * If the Method returs a valid {@link BonemealBlockSpreader}-Instance, it will override the default behaviour + * for the BoneMeal, otherwise the vanilla action will be performed. + * + * @param state The {@link BlockState} you need to test + * @return A valid spreader instance, or {@code null} + */ + @ApiStatus.Internal + public BonemealBlockSpreader blockSpreaderForState(@NotNull BlockState state) { + for (var e : taggedSpreaders.entrySet()) { + if (state.is(e.getKey())) { + return e.getValue(); + } + } + + return null; + } + + @ApiStatus.Internal + public FeatureSpreader featureSpreaderForState(@NotNull BlockState state) { + return featureSpreaders.get(state.getBlock()); + } + + @ApiStatus.Internal + public boolean runSpreaders(ItemStack itemStack, Level level, BlockPos blockPos) { + BlockState blockState = level.getBlockState(blockPos); + BonemealBlockSpreader spreader = org.betterx.bclib.api.v3.bonemeal.BonemealAPI + .INSTANCE + .blockSpreaderForState(blockState); + + if (spreader != null) { + if (spreader.isValidBonemealSpreadTarget(level, blockPos, blockState, level.isClientSide)) { + if (level instanceof ServerLevel) { + if (spreader.performBonemealSpread((ServerLevel) level, level.random, blockPos, blockState)) { + itemStack.shrink(1); + } + } + return true; + } + } + + FeatureSpreader fSpreader = org.betterx.bclib.api.v3.bonemeal.BonemealAPI + .INSTANCE + .featureSpreaderForState(blockState); + + if (fSpreader != null) { + if (fSpreader.isValidBonemealTarget(level, blockPos, blockState, level.isClientSide)) { + if (level instanceof ServerLevel) { + if (fSpreader.isBonemealSuccess(level, level.random, blockPos, blockState)) { + fSpreader.performBonemeal((ServerLevel) level, level.random, blockPos, blockState); + } + itemStack.shrink(1); + } + return true; + } + } + + return false; + } +} diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealSpreader.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealBlockSpreader.java similarity index 93% rename from src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealSpreader.java rename to src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealBlockSpreader.java index 4b2a18b5..49249cf0 100644 --- a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealSpreader.java +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealBlockSpreader.java @@ -6,7 +6,7 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.block.state.BlockState; -public interface BonemealSpreader { +public interface BonemealBlockSpreader { boolean isValidBonemealSpreadTarget(BlockGetter blockGetter, BlockPos blockPos, BlockState blockState, boolean bl); diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealGrassLike.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealGrassLike.java index 36e2423d..55d1321f 100644 --- a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealGrassLike.java +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealGrassLike.java @@ -16,11 +16,11 @@ import net.minecraft.world.level.levelgen.placement.PlacedFeature; import java.util.List; public interface BonemealGrassLike extends BonemealableBlock { - BlockState growableCoverState(); //Blocks.GRASS.defaultBlockState(); - Block hostBlock(); //this + BlockState getGrowableCoverState(); //Blocks.GRASS.defaultBlockState(); + Block getHostBlock(); //this - Holder coverFeature(); //VegetationPlacements.GRASS_BONEMEAL - List> flowerFeatures(); /*serverLevel.getBiome(currentPos) + Holder getCoverFeature(); //VegetationPlacements.GRASS_BONEMEAL + List> getFlowerFeatures(); /*serverLevel.getBiome(currentPos) .value() .getGenerationSettings() .getFlowerFeatures();*/ @@ -52,7 +52,7 @@ public interface BonemealGrassLike extends BonemealableBlock { default void performBonemeal(ServerLevel serverLevel, RandomSource random, BlockPos pos, BlockState state) { final BlockPos above = pos.above(); - final BlockState growableState = growableCoverState(); + final BlockState growableState = getGrowableCoverState(); outerLoop: for (int bonemealAttempt = 0; bonemealAttempt < 128; ++bonemealAttempt) { @@ -64,7 +64,7 @@ public interface BonemealGrassLike extends BonemealableBlock { (random.nextInt(3) - 1) * random.nextInt(3) / 2, random.nextInt(3) - 1 ); - if (!serverLevel.getBlockState(currentPos.below()).is(hostBlock()) + if (!serverLevel.getBlockState(currentPos.below()).is(getHostBlock()) || serverLevel.getBlockState(currentPos) .isCollisionShapeFullBlock(serverLevel, currentPos)) { continue outerLoop; @@ -84,14 +84,14 @@ public interface BonemealGrassLike extends BonemealableBlock { if (currentState.isAir()) { Holder boneFeature; if (canGrowFlower(random)) { - List> list = flowerFeatures(); + List> list = getFlowerFeatures(); if (list.isEmpty()) { continue; } boneFeature = ((RandomPatchConfiguration) list.get(0).config()).feature(); } else { - boneFeature = coverFeature(); + boneFeature = getCoverFeature(); } boneFeature.value() diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealNyliumLike.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealNyliumLike.java index bcbf4872..b6d7d8fa 100644 --- a/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealNyliumLike.java +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/BonemealNyliumLike.java @@ -1,7 +1,8 @@ package org.betterx.bclib.api.v3.bonemeal; +import org.betterx.bclib.api.v3.levelgen.features.BCLConfigureFeature; + import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; import net.minecraft.world.level.BlockGetter; @@ -9,12 +10,12 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.BonemealableBlock; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraft.world.level.levelgen.feature.Feature; +//adapted from NyliumBlock public interface BonemealNyliumLike extends BonemealableBlock { - Block hostBlock(); //this - Holder coverFeature(); + Block getHostBlock(); //this + BCLConfigureFeature, ?> getCoverFeature(); default boolean isValidBonemealTarget( BlockGetter blockGetter, @@ -41,12 +42,11 @@ public interface BonemealNyliumLike extends BonemealableBlock { BlockState blockState ) { final BlockState currentState = serverLevel.getBlockState(blockPos); - final BlockPos above = blockPos.above(); - final ChunkGenerator generator = serverLevel.getChunkSource().getGenerator(); - if (currentState.is(hostBlock())) { - coverFeature() - .value() - .place(serverLevel, generator, randomSource, above); + if (currentState.is(getHostBlock())) { + BCLConfigureFeature, ?> feature = getCoverFeature(); + if (feature != null) { + feature.placeInWorld(serverLevel, blockPos.above(), randomSource, true); + } } } } diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/EndStoneSpreader.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/EndStoneSpreader.java index 8f4a2517..6d9ad02c 100644 --- a/src/main/java/org/betterx/bclib/api/v3/bonemeal/EndStoneSpreader.java +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/EndStoneSpreader.java @@ -1,31 +1,12 @@ package org.betterx.bclib.api.v3.bonemeal; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.state.BlockState; +import org.betterx.bclib.api.v3.tag.BCLBlockTags; -public class EndStoneSpreader implements BonemealSpreader { - public static final EndStoneSpreader INSTANCE = new EndStoneSpreader(); +public class EndStoneSpreader extends TaggedBonemealBlockSpreader { + static final EndStoneSpreader INSTANCE = new EndStoneSpreader(); - @Override - public boolean isValidBonemealSpreadTarget( - BlockGetter blockGetter, - BlockPos blockPos, - BlockState blockState, - boolean bl - ) { - return false; + protected EndStoneSpreader() { + super(BCLBlockTags.BONEMEAL_SOURCE_END_STONE); } - @Override - public boolean performBonemealSpread( - ServerLevel serverLevel, - RandomSource randomSource, - BlockPos blockPos, - BlockState blockState - ) { - return false; - } } diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/FeatureSpreader.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/FeatureSpreader.java new file mode 100644 index 00000000..8b433ac3 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/FeatureSpreader.java @@ -0,0 +1,40 @@ +package org.betterx.bclib.api.v3.bonemeal; + +import org.betterx.bclib.api.v3.levelgen.features.BCLConfigureFeature; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.Feature; + +public class FeatureSpreader implements BonemealNyliumLike { + public final BCLConfigureFeature, ?> spreadableFeature; + public final Block hostBlock; + + public FeatureSpreader(Block hostBlock, BCLConfigureFeature, ?> spreadableFeature) { + this.spreadableFeature = spreadableFeature; + this.hostBlock = hostBlock; + } + + @Override + public boolean isValidBonemealTarget( + BlockGetter blockGetter, + BlockPos blockPos, + BlockState blockState, + boolean bl + ) { + return spreadableFeature != null + && BonemealNyliumLike.super.isValidBonemealTarget(blockGetter, blockPos, blockState, bl); + } + + @Override + public Block getHostBlock() { + return hostBlock; + } + + @Override + public BCLConfigureFeature, ?> getCoverFeature() { + return spreadableFeature; + } +} diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/NetherrackSpreader.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/NetherrackSpreader.java index 86f42859..fd73bafa 100644 --- a/src/main/java/org/betterx/bclib/api/v3/bonemeal/NetherrackSpreader.java +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/NetherrackSpreader.java @@ -1,81 +1,18 @@ package org.betterx.bclib.api.v3.bonemeal; -import org.betterx.bclib.util.WeightedList; -import org.betterx.worlds.together.tag.v3.CommonBlockTags; +import org.betterx.bclib.api.v3.tag.BCLBlockTags; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; -import java.util.HashMap; -import java.util.Map; - -public class NetherrackSpreader implements BonemealSpreader { +public class NetherrackSpreader extends TaggedBonemealBlockSpreader { public static final NetherrackSpreader INSTANCE = new NetherrackSpreader(); - public boolean isValidBonemealSpreadTarget( - BlockGetter blockGetter, - BlockPos blockPos, - BlockState blockState, - boolean bl - ) { - if (!blockGetter.getBlockState(blockPos.above()).propagatesSkylightDown(blockGetter, blockPos)) { - return false; - } else { - for (BlockPos testPos : BlockPos.betweenClosed( - blockPos.offset(-1, -1, -1), - blockPos.offset(1, 1, 1) - )) { - if (blockGetter.getBlockState(testPos).is(CommonBlockTags.NETHERRACK_SPREADABLE)) - return true; - } - return false; - } + protected NetherrackSpreader() { + super(BCLBlockTags.BONEMEAL_SOURCE_NETHERRACK); } - - public boolean performBonemealSpread( - ServerLevel serverLevel, - RandomSource randomSource, - BlockPos blockPos, - BlockState blockState - ) { - Map sourceBlocks = new HashMap<>(); - boolean hasNonVanilla = false; - for (BlockPos testPos : BlockPos.betweenClosed( - blockPos.offset(-1, -1, -1), - blockPos.offset(1, 1, 1) - )) { - BlockState state = serverLevel.getBlockState(testPos); - if (serverLevel.getBlockState(testPos).is(CommonBlockTags.NETHERRACK_SPREADABLE)) { - sourceBlocks.compute(state.getBlock(), (k, v) -> { - if (v == null) return 1; - return v + 1; - }); - } - - if (!state.is(Blocks.WARPED_NYLIUM) && state.is(Blocks.CRIMSON_NYLIUM)) { - hasNonVanilla = true; - } - } - - if (hasNonVanilla) { - WeightedList list = new WeightedList<>(); - for (Map.Entry e : sourceBlocks.entrySet()) { - list.add(e.getKey(), e.getValue()); - } - Block bl = list.get(randomSource); - if (bl != null) { - serverLevel.setBlock(blockPos, bl.defaultBlockState(), 3); - return true; - } - } - - - return false; + protected boolean hasCustomBehaviour(BlockState state) { + return !state.is(Blocks.WARPED_NYLIUM) && !state.is(Blocks.CRIMSON_NYLIUM); } } diff --git a/src/main/java/org/betterx/bclib/api/v3/bonemeal/TaggedBonemealBlockSpreader.java b/src/main/java/org/betterx/bclib/api/v3/bonemeal/TaggedBonemealBlockSpreader.java new file mode 100644 index 00000000..6b0e5b29 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v3/bonemeal/TaggedBonemealBlockSpreader.java @@ -0,0 +1,23 @@ +package org.betterx.bclib.api.v3.bonemeal; + +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +class TaggedBonemealBlockSpreader extends BlockSpreader { + public final TagKey blockTag; + + public TaggedBonemealBlockSpreader(TagKey blockTag) { + this.blockTag = blockTag; + } + + @Override + protected boolean isValidSource(BlockState state) { + return state.is(blockTag); + } + + @Override + protected boolean hasCustomBehaviour(BlockState state) { + return true; + } +} diff --git a/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLConfigureFeature.java b/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLConfigureFeature.java index e3442c50..b5ad4fba 100644 --- a/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLConfigureFeature.java +++ b/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLConfigureFeature.java @@ -55,7 +55,11 @@ public class BCLConfigureFeature, FC extends FeatureConfig } public boolean placeInWorld(ServerLevel level, BlockPos pos, RandomSource random) { - return placeInWorld(getFeature(), getConfiguration(), level, pos, random); + return placeInWorld(level, pos, random, false); + } + + public boolean placeInWorld(ServerLevel level, BlockPos pos, RandomSource random, boolean unchanged) { + return placeUnboundInWorld(getFeature(), getConfiguration(), level, pos, random, unchanged); } private static boolean placeUnboundInWorld( @@ -63,16 +67,19 @@ public class BCLConfigureFeature, FC extends FeatureConfig FeatureConfiguration config, ServerLevel level, BlockPos pos, - RandomSource random + RandomSource random, + boolean asIs ) { - if (config instanceof RandomPatchConfiguration rnd) { - var configured = rnd.feature().value().feature().value(); - feature = configured.feature(); - config = configured.config(); - } + if (!asIs) { + if (config instanceof RandomPatchConfiguration rnd) { + var configured = rnd.feature().value().feature().value(); + feature = configured.feature(); + config = configured.config(); + } - if (feature instanceof UserGrowableFeature growable) { - return growable.grow(level, pos, random, config); + if (feature instanceof UserGrowableFeature growable) { + return growable.grow(level, pos, random, config); + } } FeaturePlaceContext context = new FeaturePlaceContext( @@ -92,7 +99,7 @@ public class BCLConfigureFeature, FC extends FeatureConfig BlockPos pos, RandomSource random ) { - return placeUnboundInWorld(feature, FeatureConfiguration.NONE, level, pos, random); + return placeUnboundInWorld(feature, FeatureConfiguration.NONE, level, pos, random, true); } public static boolean placeInWorld( @@ -102,6 +109,6 @@ public class BCLConfigureFeature, FC extends FeatureConfig BlockPos pos, RandomSource random ) { - return placeUnboundInWorld(feature, config, level, pos, random); + return placeUnboundInWorld(feature, config, level, pos, random, true); } } diff --git a/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLFeatureBuilder.java b/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLFeatureBuilder.java index f5c8c048..dd53e5bf 100644 --- a/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLFeatureBuilder.java +++ b/src/main/java/org/betterx/bclib/api/v3/levelgen/features/BCLFeatureBuilder.java @@ -140,6 +140,15 @@ public abstract class BCLFeatureBuilder, FC extends Featur ); } + public static NetherForrestVegetation startBonemealNetherVegetation( + ResourceLocation featureID + ) { + return new NetherForrestVegetation( + featureID, + (NetherForestVegetationFeature) Feature.NETHER_FOREST_VEGETATION + ).spreadHeight(1).spreadWidth(3); + } + public static WithTemplates startWithTemplates( ResourceLocation featureID @@ -671,7 +680,7 @@ public abstract class BCLFeatureBuilder, FC extends Featur // is meant to prevent that... if (NoneFeatureConfiguration.NONE != null) return (FC) NoneFeatureConfiguration.NONE; - + return (FC) NoneFeatureConfiguration.INSTANCE; } return configuration; diff --git a/src/main/java/org/betterx/bclib/api/v3/levelgen/features/CommonPlacedFeatureBuilder.java b/src/main/java/org/betterx/bclib/api/v3/levelgen/features/CommonPlacedFeatureBuilder.java index d26524db..781b0218 100644 --- a/src/main/java/org/betterx/bclib/api/v3/levelgen/features/CommonPlacedFeatureBuilder.java +++ b/src/main/java/org/betterx/bclib/api/v3/levelgen/features/CommonPlacedFeatureBuilder.java @@ -420,4 +420,11 @@ abstract class CommonPlacedFeatureBuilder, FC extends Feat public BCLFeatureBuilder.RandomPatch inRandomPatch(ResourceLocation id) { return BCLFeatureBuilder.startRandomPatch(id, build()); } + + public BCLFeatureBuilder.RandomPatch randomBonemealDistribution(ResourceLocation id) { + return inRandomPatch(id) + .tries(9) + .spreadXZ(3) + .spreadY(1); + } } diff --git a/src/main/java/org/betterx/bclib/api/v3/tag/BCLBlockTags.java b/src/main/java/org/betterx/bclib/api/v3/tag/BCLBlockTags.java new file mode 100644 index 00000000..ca638a64 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v3/tag/BCLBlockTags.java @@ -0,0 +1,31 @@ +package org.betterx.bclib.api.v3.tag; + +import org.betterx.worlds.together.tag.v3.TagManager; + +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; + +import org.jetbrains.annotations.ApiStatus; + +public class BCLBlockTags { + public static final TagKey BONEMEAL_SOURCE_NETHERRACK = TagManager.BLOCKS.makeTogetherTag( + "bonemeal/source/netherrack" + ); + public static final TagKey BONEMEAL_TARGET_NETHERRACK = TagManager.BLOCKS.makeTogetherTag( + "bonemeal/target/netherrack" + ); + public static final TagKey BONEMEAL_SOURCE_END_STONE = TagManager.BLOCKS.makeTogetherTag( + "bonemeal/source/end_stone" + ); + public static final TagKey BONEMEAL_TARGET_END_STONE = TagManager.BLOCKS.makeTogetherTag( + "bonemeal/target/end_stone" + ); + + @ApiStatus.Internal + public static void ensureStaticallyLoaded() { + TagManager.BLOCKS.add(BONEMEAL_SOURCE_NETHERRACK, Blocks.WARPED_NYLIUM, Blocks.CRIMSON_NYLIUM); + TagManager.BLOCKS.add(BONEMEAL_TARGET_NETHERRACK, Blocks.NETHERRACK); + TagManager.BLOCKS.add(BONEMEAL_TARGET_END_STONE, Blocks.END_STONE); + } +} diff --git a/src/main/java/org/betterx/bclib/mixin/common/BoneMealItemMixin.java b/src/main/java/org/betterx/bclib/mixin/common/BoneMealItemMixin.java index b858f1fb..f197bb94 100644 --- a/src/main/java/org/betterx/bclib/mixin/common/BoneMealItemMixin.java +++ b/src/main/java/org/betterx/bclib/mixin/common/BoneMealItemMixin.java @@ -2,16 +2,12 @@ package org.betterx.bclib.mixin.common; import org.betterx.bclib.api.v2.BonemealAPI; import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI; -import org.betterx.bclib.api.v3.bonemeal.BonemealSpreader; -import org.betterx.bclib.api.v3.bonemeal.EndStoneSpreader; -import org.betterx.bclib.api.v3.bonemeal.NetherrackSpreader; import org.betterx.bclib.util.BlocksHelper; import org.betterx.bclib.util.MHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.core.Vec3i; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.BoneMealItem; import net.minecraft.world.item.ItemStack; @@ -71,32 +67,17 @@ public class BoneMealItemMixin { } @Inject(method = "growCrop", at = @At("HEAD"), cancellable = true) - private static void growCrop( + private static void bcl_growCrop( ItemStack itemStack, Level level, BlockPos blockPos, CallbackInfoReturnable cir ) { - BlockState blockState = level.getBlockState(blockPos); - BonemealSpreader spreader = null; - - if (blockState.is(Blocks.NETHERRACK)) { - spreader = NetherrackSpreader.INSTANCE; - } else if (blockState.is(Blocks.END_STONE)) { - spreader = EndStoneSpreader.INSTANCE; - } else if (blockState.getBlock() instanceof BonemealSpreader s) { - spreader = s; - } - - if (spreader != null) { - if (spreader.isValidBonemealSpreadTarget(level, blockPos, blockState, level.isClientSide)) { - if (level instanceof ServerLevel) { - if (spreader.performBonemealSpread((ServerLevel) level, level.random, blockPos, blockState)) { - itemStack.shrink(1); - cir.setReturnValue(true); - } - } - } + if (org.betterx.bclib.api.v3.bonemeal.BonemealAPI + .INSTANCE + .runSpreaders(itemStack, level, blockPos) + ) { + cir.setReturnValue(true); } } diff --git a/src/main/java/org/betterx/worlds/together/tag/v3/CommonBlockTags.java b/src/main/java/org/betterx/worlds/together/tag/v3/CommonBlockTags.java index 81b1f2aa..9f2ee4aa 100644 --- a/src/main/java/org/betterx/worlds/together/tag/v3/CommonBlockTags.java +++ b/src/main/java/org/betterx/worlds/together/tag/v3/CommonBlockTags.java @@ -35,12 +35,7 @@ public class CommonBlockTags { public static final TagKey TERRAIN = TagManager.BLOCKS.makeCommonTag("terrain"); public static final TagKey NETHER_TERRAIN = TagManager.BLOCKS.makeCommonTag("nether_terrain"); - public static final TagKey NETHERRACK_SPREADABLE = TagManager.BLOCKS.makeCommonTag( - "netherrack_spreadable"); - static void prepareTags() { - TagManager.BLOCKS.add(NETHERRACK_SPREADABLE, Blocks.WARPED_NYLIUM, Blocks.CRIMSON_NYLIUM); - TagManager.BLOCKS.add(SCULK_LIKE, Blocks.SCULK); TagManager.BLOCKS.addOtherTags(DRAGON_IMMUNE, BlockTags.DRAGON_IMMUNE); diff --git a/src/main/java/org/betterx/worlds/together/tag/v3/TagRegistry.java b/src/main/java/org/betterx/worlds/together/tag/v3/TagRegistry.java index 88f4b2bc..493626a0 100644 --- a/src/main/java/org/betterx/worlds/together/tag/v3/TagRegistry.java +++ b/src/main/java/org/betterx/worlds/together/tag/v3/TagRegistry.java @@ -205,6 +205,10 @@ public class TagRegistry { return creatTagKey(new ResourceLocation("c", name)); } + public TagKey makeTogetherTag(String name) { + return creatTagKey(WorldsTogether.makeID(name)); + } + public void addUntyped(TagKey tagID, ResourceLocation... elements) { if (isFrozen) WorldsTogether.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen."); Set set = getSetForTag(tagID);