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..e819e7515 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,8 @@ 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 SURFACE_SPREADING_BLOCK = Key.from("craftengine:surface_spreading_block"); + public static final Key SNOWY_BLOCK = Key.from("craftengine:snowy_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -86,5 +88,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY); register(SEAT_BLOCK, SeatBlockBehavior.FACTORY); + register(SURFACE_SPREADING_BLOCK, SurfaceSpreadingBlockBehavior.FACTORY); + register(SNOWY_BLOCK, SnowyBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SnowyBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SnowyBlockBehavior.java new file mode 100644 index 000000000..6540c9727 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SnowyBlockBehavior.java @@ -0,0 +1,54 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +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.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +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.ResourceConfigUtils; + +import java.util.Map; +import java.util.concurrent.Callable; + +public class SnowyBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final BooleanProperty snowyProperty; + + public SnowyBlockBehavior(CustomBlock customBlock, BooleanProperty snowyProperty) { + super(customBlock); + this.snowyProperty = snowyProperty; + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (args[updateShape$direction] != CoreReflections.instance$Direction$UP) return superMethod.call(); + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (state == null || state.isEmpty()) return superMethod.call(); + return state.with(this.snowyProperty, isSnowySetting(args[updateShape$neighborState])); + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos().above())); + return state.with(this.snowyProperty, isSnowySetting(blockState)); + } + + private static boolean isSnowySetting(Object state) { + return FastNMS.INSTANCE.method$BlockStateBase$is(state, MTagKeys.Block$SNOW); + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + BooleanProperty snowyProperty = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("snowy"), "warning.config.block.behavior.snowy.missing_snowy"); + return new SnowyBlockBehavior(block, snowyProperty); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SurfaceSpreadingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SurfaceSpreadingBlockBehavior.java new file mode 100644 index 000000000..9c1a16a21 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SurfaceSpreadingBlockBehavior.java @@ -0,0 +1,90 @@ +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.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.BooleanProperty; +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 SurfaceSpreadingBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final int requiredLight; + private final LazyReference baseBlock; + + public SurfaceSpreadingBlockBehavior(CustomBlock customBlock, int requiredLight, String baseBlock) { + super(customBlock); + this.requiredLight = requiredLight; + this.baseBlock = LazyReference.lazyReference(() -> Objects.requireNonNull(BukkitBlockManager.instance().createBlockState(baseBlock)).literalObject()); + } + + @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.baseBlock.get(), 3); + return; + } + if (FastNMS.INSTANCE.method$LevelReader$getMaxLocalRawBrightness(level, FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP)) < this.requiredLight) 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.baseBlock.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 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 requiredLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("required-light", 9), "required-light"); + String baseBlock = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("base-block", "minecraft:dirt"), "warning.config.block.behavior.surface_spreading.missing_base_block"); + return new SurfaceSpreadingBlockBehavior(block, requiredLight, baseBlock); + } + } +} 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..b69c610d0 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -353,6 +353,8 @@ 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.surface_spreading.missing_base_block: "Issue found in file - The block '' is missing the required 'base-block' argument for 'surface_spreading_block' behavior." +warning.config.block.behavior.snowy.missing_snowy: "Issue found in file - The block '' is missing the required 'snowy' property for 'snowy_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..886cb003e 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -353,6 +353,8 @@ 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.surface_spreading.missing_base_block: "在文件 发现问题 - 方块 '' 的 'surface_spreading_block' 行为缺少必需的 'base-block' 选项" +warning.config.block.behavior.snowy.missing_snowy: "在文件 发现问题 - 方块 '' 的 'snowy_block' 行为缺少必需的 'snowy' 属性" 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