[Feature] New Bonemeal API
This commit is contained in:
parent
41b1d9eb68
commit
5b99e0be53
7 changed files with 328 additions and 1 deletions
|
@ -0,0 +1,103 @@
|
|||
package org.betterx.bclib.api.v3.bonemeal;
|
||||
|
||||
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;
|
||||
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.levelgen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.RandomPatchConfiguration;
|
||||
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
|
||||
|
||||
Holder<PlacedFeature> coverFeature(); //VegetationPlacements.GRASS_BONEMEAL
|
||||
List<ConfiguredFeature<?, ?>> flowerFeatures(); /*serverLevel.getBiome(currentPos)
|
||||
.value()
|
||||
.getGenerationSettings()
|
||||
.getFlowerFeatures();*/
|
||||
|
||||
default boolean canGrowFlower(RandomSource random) {
|
||||
return random.nextInt(8) == 0;
|
||||
}
|
||||
default boolean canGrowCover(RandomSource random) {
|
||||
return random.nextInt(10) == 0;
|
||||
}
|
||||
|
||||
default boolean isValidBonemealTarget(
|
||||
BlockGetter blockGetter,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState,
|
||||
boolean bl
|
||||
) {
|
||||
return blockGetter.getBlockState(blockPos.above()).isAir();
|
||||
}
|
||||
|
||||
default boolean isBonemealSuccess(
|
||||
Level level,
|
||||
RandomSource randomSource,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void performBonemeal(ServerLevel serverLevel, RandomSource random, BlockPos pos, BlockState state) {
|
||||
final BlockPos above = pos.above();
|
||||
final BlockState growableState = growableCoverState();
|
||||
|
||||
outerLoop:
|
||||
for (int bonemealAttempt = 0; bonemealAttempt < 128; ++bonemealAttempt) {
|
||||
BlockPos currentPos = above;
|
||||
|
||||
for (int j = 0; j < bonemealAttempt / 16; ++j) {
|
||||
currentPos = currentPos.offset(
|
||||
random.nextInt(3) - 1,
|
||||
(random.nextInt(3) - 1) * random.nextInt(3) / 2,
|
||||
random.nextInt(3) - 1
|
||||
);
|
||||
if (!serverLevel.getBlockState(currentPos.below()).is(hostBlock())
|
||||
|| serverLevel.getBlockState(currentPos)
|
||||
.isCollisionShapeFullBlock(serverLevel, currentPos)) {
|
||||
continue outerLoop;
|
||||
}
|
||||
}
|
||||
|
||||
BlockState currentState = serverLevel.getBlockState(currentPos);
|
||||
if (currentState.is(growableState.getBlock()) && canGrowCover(random)) {
|
||||
((BonemealableBlock) growableState.getBlock()).performBonemeal(
|
||||
serverLevel,
|
||||
random,
|
||||
currentPos,
|
||||
currentState
|
||||
);
|
||||
}
|
||||
|
||||
if (currentState.isAir()) {
|
||||
Holder<PlacedFeature> boneFeature;
|
||||
if (canGrowFlower(random)) {
|
||||
List<ConfiguredFeature<?, ?>> list = flowerFeatures();
|
||||
if (list.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boneFeature = ((RandomPatchConfiguration) list.get(0).config()).feature();
|
||||
} else {
|
||||
boneFeature = coverFeature();
|
||||
}
|
||||
|
||||
boneFeature.value()
|
||||
.place(serverLevel, serverLevel.getChunkSource().getGenerator(), random, currentPos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package org.betterx.bclib.api.v3.bonemeal;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
public interface BonemealNyliumLike extends BonemealableBlock {
|
||||
Block hostBlock(); //this
|
||||
Holder<PlacedFeature> coverFeature();
|
||||
|
||||
default boolean isValidBonemealTarget(
|
||||
BlockGetter blockGetter,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState,
|
||||
boolean bl
|
||||
) {
|
||||
return blockGetter.getBlockState(blockPos.above()).isAir();
|
||||
}
|
||||
|
||||
default boolean isBonemealSuccess(
|
||||
Level level,
|
||||
RandomSource randomSource,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void performBonemeal(
|
||||
ServerLevel serverLevel,
|
||||
RandomSource randomSource,
|
||||
BlockPos blockPos,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
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;
|
||||
|
||||
public interface BonemealSpreader {
|
||||
boolean isValidBonemealSpreadTarget(BlockGetter blockGetter, BlockPos blockPos, BlockState blockState, boolean bl);
|
||||
|
||||
|
||||
boolean performBonemealSpread(
|
||||
ServerLevel serverLevel,
|
||||
RandomSource randomSource,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState
|
||||
);
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
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;
|
||||
|
||||
public class EndStoneSpreader implements BonemealSpreader {
|
||||
public static final EndStoneSpreader INSTANCE = new EndStoneSpreader();
|
||||
|
||||
@Override
|
||||
public boolean isValidBonemealSpreadTarget(
|
||||
BlockGetter blockGetter,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState,
|
||||
boolean bl
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performBonemealSpread(
|
||||
ServerLevel serverLevel,
|
||||
RandomSource randomSource,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.betterx.bclib.api.v3.bonemeal;
|
||||
|
||||
import org.betterx.bclib.util.WeightedList;
|
||||
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
|
||||
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean performBonemealSpread(
|
||||
ServerLevel serverLevel,
|
||||
RandomSource randomSource,
|
||||
BlockPos blockPos,
|
||||
BlockState blockState
|
||||
) {
|
||||
Map<Block, Integer> 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<Block> list = new WeightedList<>();
|
||||
for (Map.Entry<Block, Integer> 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;
|
||||
}
|
||||
}
|
|
@ -2,14 +2,19 @@ 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;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
@ -33,7 +38,7 @@ public class BoneMealItemMixin {
|
|||
@Inject(method = "useOn", at = @At("HEAD"), cancellable = true)
|
||||
private void bclib_onUse(UseOnContext context, CallbackInfoReturnable<InteractionResult> info) {
|
||||
Level world = context.getLevel();
|
||||
BlockPos blockPos = context.getClickedPos();
|
||||
final BlockPos blockPos = context.getClickedPos();
|
||||
if (!world.isClientSide()) {
|
||||
if (BonemealAPI.isTerrain(world.getBlockState(blockPos).getBlock())) {
|
||||
boolean consume = false;
|
||||
|
@ -65,6 +70,36 @@ public class BoneMealItemMixin {
|
|||
}
|
||||
}
|
||||
|
||||
@Inject(method = "growCrop", at = @At("HEAD"), cancellable = true)
|
||||
private static void growCrop(
|
||||
ItemStack itemStack,
|
||||
Level level,
|
||||
BlockPos blockPos,
|
||||
CallbackInfoReturnable<Boolean> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean bclib_growLandGrass(Level level, BlockPos pos) {
|
||||
int y1 = pos.getY() + 3;
|
||||
|
|
|
@ -35,7 +35,12 @@ public class CommonBlockTags {
|
|||
public static final TagKey<Block> TERRAIN = TagManager.BLOCKS.makeCommonTag("terrain");
|
||||
public static final TagKey<Block> NETHER_TERRAIN = TagManager.BLOCKS.makeCommonTag("nether_terrain");
|
||||
|
||||
public static final TagKey<Block> 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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue