From e315df82f8d800afcc3656a2f4dc200ac350152b Mon Sep 17 00:00:00 2001 From: Arubik <102335860+ArubikU@users.noreply.github.com> Date: Mon, 4 Aug 2025 18:47:37 -0500 Subject: [PATCH 1/5] ChangeOverTimeBlockBehavior usefull for features like oxidizing block --- .../block/behavior/BukkitBlockBehaviors.java | 3 +- .../behavior/ChangeOverTimeBlockBehavior.java | 77 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java 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 3f1d586b7..6e1b23209 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 @@ -27,7 +27,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block"); public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block"); public static final Key DOUBLE_BLOCK = Key.from("craftengine:double_block"); - + public static final Key CHANGE_OVER_TIME_BLOCK = Key.from("craftengine:change_over_time_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); register(FALLING_BLOCK, FallingBlockBehavior.FACTORY); @@ -52,5 +52,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY); register(PRESSURE_PLATE_BLOCK, PressurePlateBlockBehavior.FACTORY); register(DOUBLE_BLOCK, DoubleBlockBehavior.FACTORY); + register(CHANGE_OVER_TIME_BLOCK,ChangeOverTimeBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java new file mode 100644 index 000000000..c7e4c2707 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java @@ -0,0 +1,77 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Callable; + +import org.bukkit.GameEvent; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.util.Vector; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; +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.UpdateOption; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.sparrow.nbt.CompoundTag; + +public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior{ + public static final Factory FACTORY = new Factory(); + private final float delay; + private final Key nextBlock; + + public ChangeOverTimeBlockBehavior(CustomBlock customBlock, float delay, Key nextBlock) { + super(customBlock); + this.delay = delay; + this.nextBlock = nextBlock; + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (shouldChange(args)) { + Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(nextBlock); + if (optionalNewCustomBlock.isPresent()) { + + Object blockState = args[0]; + World level = (World) args[1]; + BlockPos blockPos = (BlockPos) args[2]; + Optional optionalCurrentState = BlockStateUtils.getOptionalCustomBlockState(blockState); + if (optionalCurrentState.isEmpty()) { + return; + } + CompoundTag compoundTag = optionalCurrentState.get().propertiesNbt(); + ImmutableBlockState newState = optionalNewCustomBlock.get().getBlockState(compoundTag); + BukkitBlockInWorld blockInWorld = (BukkitBlockInWorld) level.getBlockAt(LocationUtils.fromBlockPos(blockPos)); + BlockFormEvent event = new BlockFormEvent(blockInWorld.block(), BlockStateUtils.fromBlockData(newState.customBlockState().handle()).createBlockState()); + if(event.callEvent()){ + + FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags()); + blockInWorld.block().getWorld().sendGameEvent(null, GameEvent.BLOCK_CHANGE, new Vector(blockPos.x(), blockPos.y(), blockPos.z())); + } + } + } + } + + private boolean shouldChange(Object[] args) { + return RandomUtils.generateRandomFloat(0F, 1F) < this.delay; + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + float delay = Float.valueOf(arguments.getOrDefault("delay", 0.05688889F).toString()); + String nextBlock = arguments.getOrDefault("next-block", "minecraft:air").toString(); + return new ChangeOverTimeBlockBehavior(block, delay, Key.from(nextBlock)); + } + } +} From 2dfbdd3a5b18c8c323f0201609ee86ab3ca2b539 Mon Sep 17 00:00:00 2001 From: Arubik <102335860+ArubikU@users.noreply.github.com> Date: Mon, 4 Aug 2025 18:50:43 -0500 Subject: [PATCH 2/5] Update BukkitBlockBehaviors.java --- .../craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java | 2 -- 1 file changed, 2 deletions(-) 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 f1735e400..379a85575 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 @@ -26,7 +26,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key SLAB_BLOCK = Key.from("craftengine:slab_block"); public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block"); public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block"); - public static final Key DOUBLE_BLOCK = Key.from("craftengine:double_block"); public static final Key DOUBLE_HIGH_BLOCK = Key.from("craftengine:double_high_block"); public static final Key CHANGE_OVER_TIME_BLOCK = Key.from("craftengine:change_over_time_block"); public static void init() { @@ -52,7 +51,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(SLAB_BLOCK, SlabBlockBehavior.FACTORY); register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY); register(PRESSURE_PLATE_BLOCK, PressurePlateBlockBehavior.FACTORY); - register(DOUBLE_BLOCK, DoubleBlockBehavior.FACTORY); register(DOUBLE_HIGH_BLOCK, DoubleHighBlockBehavior.FACTORY); register(CHANGE_OVER_TIME_BLOCK,ChangeOverTimeBlockBehavior.FACTORY); } From 26b478a9ea97659a7fdbce723a1b8e07cbf6ab07 Mon Sep 17 00:00:00 2001 From: Arubik <102335860+ArubikU@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:37:47 -0500 Subject: [PATCH 3/5] Update ChangeOverTimeBlockBehavior.java --- .../behavior/ChangeOverTimeBlockBehavior.java | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java index c7e4c2707..d79531deb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java @@ -20,11 +20,12 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; import net.momirealms.sparrow.nbt.CompoundTag; -public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior{ +public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final float delay; private final Key nextBlock; @@ -37,27 +38,21 @@ public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior{ @Override public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - if (shouldChange(args)) { - Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(nextBlock); - if (optionalNewCustomBlock.isPresent()) { - - Object blockState = args[0]; - World level = (World) args[1]; - BlockPos blockPos = (BlockPos) args[2]; - Optional optionalCurrentState = BlockStateUtils.getOptionalCustomBlockState(blockState); - if (optionalCurrentState.isEmpty()) { - return; - } - CompoundTag compoundTag = optionalCurrentState.get().propertiesNbt(); - ImmutableBlockState newState = optionalNewCustomBlock.get().getBlockState(compoundTag); - BukkitBlockInWorld blockInWorld = (BukkitBlockInWorld) level.getBlockAt(LocationUtils.fromBlockPos(blockPos)); - BlockFormEvent event = new BlockFormEvent(blockInWorld.block(), BlockStateUtils.fromBlockData(newState.customBlockState().handle()).createBlockState()); - if(event.callEvent()){ - - FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags()); - blockInWorld.block().getWorld().sendGameEvent(null, GameEvent.BLOCK_CHANGE, new Vector(blockPos.x(), blockPos.y(), blockPos.z())); - } - } + if(!shouldChange(args)) return; + Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(nextBlock); + if (!optionalNewCustomBlock.isPresent()) return; + Object blockState = args[0]; + World level = (World) args[1]; + BlockPos blockPos = (BlockPos) args[2]; + Optional optionalCurrentState = BlockStateUtils .getOptionalCustomBlockState(blockState); + if (optionalCurrentState.isEmpty()) return; + CompoundTag compoundTag = optionalCurrentState.get().propertiesNbt(); + ImmutableBlockState newState = optionalNewCustomBlock.get().getBlockState(compoundTag); + BukkitBlockInWorld blockInWorld = (BukkitBlockInWorld) level.getBlockAt(LocationUtils.fromBlockPos(blockPos)); + BlockFormEvent event = new BlockFormEvent(blockInWorld.block(),BlockStateUtils.fromBlockData(newState.customBlockState().handle()).createBlockState()); + if (event.callEvent()) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags()); + blockInWorld.block().getWorld().sendGameEvent(null, GameEvent.BLOCK_CHANGE, new Vector(blockPos.x(), blockPos.y(), blockPos.z())); } } @@ -66,12 +61,11 @@ public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior{ } public static class Factory implements BlockBehaviorFactory { - @Override public BlockBehavior create(CustomBlock block, Map arguments) { float delay = Float.valueOf(arguments.getOrDefault("delay", 0.05688889F).toString()); - String nextBlock = arguments.getOrDefault("next-block", "minecraft:air").toString(); - return new ChangeOverTimeBlockBehavior(block, delay, Key.from(nextBlock)); + Key nextBlock = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("next-block", "minecraft:air"), "warning.config.block.behavior.change_over_time_block_missing_next_block")); + return new ChangeOverTimeBlockBehavior(block, delay, nextBlock); } } } From 4e23f53784dba4d6a3a9dcbafb42f61f9a3f9721 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Mon, 11 Aug 2025 08:26:41 +0800 Subject: [PATCH 4/5] Update BukkitBlockBehaviors.java --- .../craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java | 1 + 1 file changed, 1 insertion(+) 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 379a85575..d914ae7df 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 @@ -28,6 +28,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block"); public static final Key DOUBLE_HIGH_BLOCK = Key.from("craftengine:double_high_block"); public static final Key CHANGE_OVER_TIME_BLOCK = Key.from("craftengine:change_over_time_block"); + public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); register(FALLING_BLOCK, FallingBlockBehavior.FACTORY); From 644a9a646684d162503f95aa895e50dec91e549d Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 11 Aug 2025 09:40:46 +0800 Subject: [PATCH 5/5] =?UTF-8?q?refactor(block):=20=E9=87=8D=E6=9E=84=20Cha?= =?UTF-8?q?ngeOverTimeBlockBehavior=20=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/ChangeOverTimeBlockBehavior.java | 71 ++++++------------- .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 1 + 3 files changed, 25 insertions(+), 48 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java index d79531deb..78335c893 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java @@ -1,71 +1,46 @@ package net.momirealms.craftengine.bukkit.block.behavior; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; +import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -import org.bukkit.GameEvent; -import org.bukkit.event.block.BlockFormEvent; -import org.bukkit.util.Vector; - -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; -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.UpdateOption; -import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.RandomUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.World; -import net.momirealms.sparrow.nbt.CompoundTag; - public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private final float delay; + private final float changeSpeed; private final Key nextBlock; - public ChangeOverTimeBlockBehavior(CustomBlock customBlock, float delay, Key nextBlock) { + public ChangeOverTimeBlockBehavior(CustomBlock customBlock, float changeSpeed, Key nextBlock) { super(customBlock); - this.delay = delay; + this.changeSpeed = changeSpeed; this.nextBlock = nextBlock; } @Override - public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - if(!shouldChange(args)) return; - Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(nextBlock); - if (!optionalNewCustomBlock.isPresent()) return; - Object blockState = args[0]; - World level = (World) args[1]; - BlockPos blockPos = (BlockPos) args[2]; - Optional optionalCurrentState = BlockStateUtils .getOptionalCustomBlockState(blockState); - if (optionalCurrentState.isEmpty()) return; - CompoundTag compoundTag = optionalCurrentState.get().propertiesNbt(); - ImmutableBlockState newState = optionalNewCustomBlock.get().getBlockState(compoundTag); - BukkitBlockInWorld blockInWorld = (BukkitBlockInWorld) level.getBlockAt(LocationUtils.fromBlockPos(blockPos)); - BlockFormEvent event = new BlockFormEvent(blockInWorld.block(),BlockStateUtils.fromBlockData(newState.customBlockState().handle()).createBlockState()); - if (event.callEvent()) { - FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags()); - blockInWorld.block().getWorld().sendGameEvent(null, GameEvent.BLOCK_CHANGE, new Vector(blockPos.x(), blockPos.y(), blockPos.z())); - } - } - - private boolean shouldChange(Object[] args) { - return RandomUtils.generateRandomFloat(0F, 1F) < this.delay; + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws ReflectiveOperationException { + if (RandomUtils.generateRandomFloat(0F, 1F) >= this.changeSpeed) return; + Optional nextState = BukkitBlockManager.instance().blockById(this.nextBlock) + .map(CustomBlock::defaultState) + .map(ImmutableBlockState::customBlockState) + .map(BlockStateWrapper::handle); + if (nextState.isEmpty()) return; + CraftBukkitReflections.method$CraftEventFactory$handleBlockFormEvent.invoke(null, args[1], args[2], nextState.get(), UpdateOption.UPDATE_ALL.flags()); } public static class Factory implements BlockBehaviorFactory { + @Override public BlockBehavior create(CustomBlock block, Map arguments) { - float delay = Float.valueOf(arguments.getOrDefault("delay", 0.05688889F).toString()); - Key nextBlock = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("next-block", "minecraft:air"), "warning.config.block.behavior.change_over_time_block_missing_next_block")); - return new ChangeOverTimeBlockBehavior(block, delay, nextBlock); + float changeSpeed = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("change-speed", 0.05688889F), "change-speed"); + Key nextBlock = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("next-block", "minecraft:air"), "warning.config.block.behavior.change_over_time_block.missing_next_block")); + return new ChangeOverTimeBlockBehavior(block, changeSpeed, nextBlock); } } } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 8a428d817..93b03f5c1 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -299,6 +299,7 @@ warning.config.block.behavior.stairs.missing_shape: "Issue found in file warning.config.block.behavior.pressure_plate.missing_powered: "Issue found in file - The block '' is missing the required 'powered' property for 'pressure_plate_block' behavior." warning.config.block.behavior.grass.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'grass_block' behavior." warning.config.block.behavior.double_high.missing_half: "Issue found in file - The block '' is missing the required 'half' property for 'double_block' behavior." +warning.config.block.behavior.change_over_time_block.missing_next_block: "Issue found in file - The block '' is missing the required 'next_block' property for 'change_over_time_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.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" warning.config.model.generation.invalid_gui_light: "Issue found in file - The config '' is using an invalid gui-light option '' in 'generation' section. Allowed gui light options: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 3512ddf1b..b24d301a4 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -299,6 +299,7 @@ warning.config.block.behavior.stairs.missing_shape: "在文件 warning.config.block.behavior.pressure_plate.missing_powered: "在文件 发现问题 - 方块 '' 的 'pressure_plate_block' 行为缺少必需的 'powered' 属性" warning.config.block.behavior.grass.missing_feature: "在文件 发现问题 - 方块 '' 的 'grass_block' 行为缺少必需的 'feature' 参数" warning.config.block.behavior.double_high.missing_half: "在文件 发现问题 - 方块 '' 的 'double_block' 行为缺少必需的 'half' 属性" +warning.config.block.behavior.change_over_time_block.missing_next_block: "在文件 发现问题 - 方块 '' 的 'change_over_time_block' 行为缺少必需的 'next-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 位置类型 ''. 可用展示类型: []"