diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 4bb3daf89..dbd0533c1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -44,6 +44,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block"); public static final Key BUDDING_BLOCK = Key.from("craftengine:budding_block"); public static final Key SEAT_BLOCK = Key.from("craftengine:seat_block"); + public static final Key SPREADING_BLOCK = Key.from("craftengine:spreading_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -86,5 +87,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY); register(SEAT_BLOCK, SeatBlockBehavior.FACTORY); + register(SPREADING_BLOCK, SpreadingBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SpreadingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SpreadingBlockBehavior.java new file mode 100644 index 000000000..faa138120 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SpreadingBlockBehavior.java @@ -0,0 +1,109 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MTagKeys; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.BooleanProperty; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.util.LazyReference; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Callable; + +public class SpreadingBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final int spreadLight; + private final LazyReference spreadBlock; + + public SpreadingBlockBehavior(CustomBlock customBlock, int spreadLight, String spreadBlock) { + super(customBlock); + this.spreadLight = spreadLight; + this.spreadBlock = LazyReference.lazyReference(() -> Objects.requireNonNull(BukkitBlockManager.instance().createBlockState(spreadBlock)).literalObject()); + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (args[updateShape$direction] != CoreReflections.instance$Direction$UP) return superMethod.call(); + return BlockStateUtils.toBlockStateWrapper(args[0]).withProperty("snowy", String.valueOf(isSnowySetting(args[updateShape$neighborState]))).literalObject(); + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + BooleanProperty snowy = (BooleanProperty) this.block().getProperty("snowy"); + if (snowy == null) return state; + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos().above())); + return state.with(snowy, isSnowySetting(blockState)); + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + if (!canBeGrass(state, level, pos)) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, this.spreadBlock.get(), 3); + return; + } + if (FastNMS.INSTANCE.method$LevelReader$getMaxLocalRawBrightness(level, FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP)) < this.spreadLight) return; + ImmutableBlockState blockState = this.block().defaultState(); + BooleanProperty snowy = (BooleanProperty) this.block().getProperty("snowy"); + for (int i = 0; i < 4; i++) { + Object blockPos = FastNMS.INSTANCE.method$BlockPos$offset(pos, RandomUtils.generateRandomInt(-1, 2), RandomUtils.generateRandomInt(-3, 2), RandomUtils.generateRandomInt(-1, 2)); + if (FastNMS.INSTANCE.method$BlockStateBase$isBlock(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos), FastNMS.INSTANCE.method$BlockState$getBlock(this.spreadBlock.get())) && canPropagate(state, level, blockPos)) { + if (snowy != null) blockState = blockState.with(snowy, FastNMS.INSTANCE.method$BlockStateBase$isBlock(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP)), MBlocks.SNOW)); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, blockState.customBlockState().literalObject(), 3); + } + } + } + + private static boolean canBeGrass(Object state, Object level, Object pos) { + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos); + if (FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.SNOW) && ((Integer) FastNMS.INSTANCE.method$StateHolder$getValue(blockState, CoreReflections.instance$SnowLayerBlock$LAYERS)) == 1) return true; + else if (FastNMS.INSTANCE.field$FluidState$amount(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(blockState)) == 8) return false; + else { + return FastNMS.INSTANCE.method$LightEngine$getLightBlockInto( + VersionHelper.isOrAbove1_21_2() ? null : level, + state, + VersionHelper.isOrAbove1_21_2() ? null : pos, + blockState, + VersionHelper.isOrAbove1_21_2() ? null : blockPos, + CoreReflections.instance$Direction$UP, + FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getLightBlock( + blockState, + VersionHelper.isOrAbove1_21_2() ? null : level, + VersionHelper.isOrAbove1_21_2() ? null : pos + ) + ) < 15; + } + } + + private static boolean isSnowySetting(Object state) { + return FastNMS.INSTANCE.method$BlockStateBase$is(state, MTagKeys.Block$SNOW); + } + + private static boolean canPropagate(Object state, Object level, Object pos) { + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP); + return canBeGrass(state, level, pos) && !FastNMS.INSTANCE.method$FluidState$is(FastNMS.INSTANCE.method$BlockGetter$getFluidState(level, blockPos), MTagKeys.Fluid$WATER); + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + int spreadLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("spread-light", 9), "spread-light"); + String spreadBlock = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("spread-block", "minecraft:dirt"), "warning.config.block.behavior.spreading.missing_spread_block"); + return new SpreadingBlockBehavior(block, spreadLight, spreadBlock); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java index 3f444599e..fb818baa7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java @@ -7,12 +7,14 @@ import java.util.Objects; public final class MTagKeys { private MTagKeys() {} + public static final Object Fluid$WATER = create(MRegistries.FLUID, "water"); public static final Object Item$WOOL = create(MRegistries.ITEM, "wool"); public static final Object Block$WALLS = create(MRegistries.BLOCK, "walls"); public static final Object Block$SHULKER_BOXES = create(MRegistries.BLOCK, "shulker_boxes"); public static final Object Block$FENCES = create(MRegistries.BLOCK, "fences"); public static final Object Block$WOODEN_FENCES = create(MRegistries.BLOCK, "wooden_fences"); public static final Object Block$DIRT = create(MRegistries.BLOCK, "dirt"); + public static final Object Block$SNOW = create(MRegistries.BLOCK, "snow"); private static Object create(Object registry, String location) { Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location); diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 93b5e5c72..b77e3c8dc 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -353,6 +353,7 @@ warning.config.block.behavior.attached_stem.missing_facing: "Issue found warning.config.block.behavior.attached_stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_stem: "Issue found in file - The block '' is missing the required 'stem' argument for 'attached_stem_block' behavior." warning.config.block.behavior.chime.missing_sounds_projectile_hit: "Issue found in file - The block '' is missing the required 'sounds.projectile-hit' argument for 'chime_block' behavior." +warning.config.block.behavior.spreading.missing_spread_block: "Issue found in file - The block '' is missing the required 'spread-block' argument for 'spreading_block' behavior." warning.config.model.generation.missing_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." warning.config.model.generation.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." warning.config.model.generation.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index b2a6c3685..7312dce1b 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -353,6 +353,7 @@ warning.config.block.behavior.attached_stem.missing_facing: "在文件 < warning.config.block.behavior.attached_stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项" warning.config.block.behavior.attached_stem.missing_stem: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项" warning.config.block.behavior.chime.missing_sounds_projectile_hit: "在文件 发现问题 - 方块 '' 的 'chime_block' 行为缺少必需的 'sounds.projectile-hit' 选项" +warning.config.block.behavior.spreading.missing_spread_block: "在文件 发现问题 - 方块 '' 的 'spreading_block' 行为缺少必需的 'spread-block' 选项" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" diff --git a/gradle.properties b/gradle.properties index 0ec0adef5..fc1dc340b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G # Rule: [major update].[feature update].[bug fix] project_version=0.0.65.6 config_version=53 -lang_version=37 +lang_version=38 project_group=net.momirealms latest_supported_version=1.21.10 @@ -49,7 +49,7 @@ byte_buddy_version=1.17.8 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=1.0.4 -nms_helper_version=1.0.127 +nms_helper_version=1.0.128 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5