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 34435ad14..abec0ded2 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 @@ -32,6 +32,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key TOGGLEABLE_LAMP_BLOCK = Key.from("craftengine:toggleable_lamp_block"); public static final Key SOFA_BLOCK = Key.from("craftengine:sofa_block"); public static final Key BOUNCING_BLOCK = Key.from("craftengine:bouncing_block"); + public static final Key WALL_ATTACHED_BLOCK = Key.from("craftengine:wall_attached_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -62,5 +63,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(TOGGLEABLE_LAMP_BLOCK, ToggleableLampBlockBehavior.FACTORY); register(SOFA_BLOCK, SofaBlockBehavior.FACTORY); register(BOUNCING_BLOCK, BouncingBlockBehavior.FACTORY); + register(WALL_ATTACHED_BLOCK, WallAttachedBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallAttachedBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallAttachedBlockBehavior.java new file mode 100644 index 000000000..2abf17eaf --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallAttachedBlockBehavior.java @@ -0,0 +1,83 @@ +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.MBlocks; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +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.Property; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.World; + +import java.util.Map; +import java.util.concurrent.Callable; + +public class WallAttachedBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property facingProperty; + + public WallAttachedBlockBehavior(CustomBlock customBlock, Property facingProperty) { + super(customBlock); + this.facingProperty = facingProperty; + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (state == null) return args[0]; + WallAttachedBlockBehavior behavior = state.behavior().getAs(WallAttachedBlockBehavior.class).orElse(null); + if (behavior == null) return state; + HorizontalDirection direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]).opposite().toHorizontalDirection(); + return direction == state.get(behavior.facingProperty) && !FastNMS.INSTANCE.method$BlockStateBase$canSurvive(args[0], args[updateShape$level], args[updateShape$blockPos]) ? MBlocks.AIR$defaultState : args[0]; + } + + @Override + public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (state == null) return false; + WallAttachedBlockBehavior behavior = state.behavior().getAs(WallAttachedBlockBehavior.class).orElse(null); + if (behavior == null) return false; + HorizontalDirection direction = state.get(behavior.facingProperty); + BlockPos blockPos = LocationUtils.fromBlockPos(args[2]).relative(direction.opposite().toDirection()); + Object nmsPos = LocationUtils.toBlockPos(blockPos); + Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[1], nmsPos); + return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, args[1], nmsPos, DirectionUtils.toNMSDirection(direction.opposite().toDirection()), CoreReflections.instance$SupportType$FULL); + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + WallAttachedBlockBehavior behavior = state.behavior().getAs(WallAttachedBlockBehavior.class).orElse(null); + if (behavior == null) return null; + World level = context.getLevel(); + BlockPos clickedPos = context.getClickedPos(); + Direction[] nearestLookingDirections = context.getNearestLookingDirections(); + for (Direction direction : nearestLookingDirections) { + if (direction.axis().isHorizontal()) { + state = state.with(behavior.facingProperty, direction.opposite().toHorizontalDirection()); + if (FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state.customBlockState().literalObject(), level.serverWorld(), LocationUtils.toBlockPos(clickedPos))) { + return state; + } + } + } + return null; + } + + public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings("unchecked") + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Property facing = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.wall_attached.missing_facing"); + return new WallAttachedBlockBehavior(block, facing); + } + } +} diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index bde6e388d..6a03f9f8e 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -316,6 +316,7 @@ warning.config.block.behavior.pressure_plate.missing_powered: "Issue fou 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.missing_next_block: "Issue found in file - The block '' is missing the required 'next_block' property for 'change_over_time_block' behavior." +warning.config.block.behavior.wall_attached.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'wall_attached_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 b1f2fb30d..6ccce87d5 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -311,6 +311,7 @@ warning.config.block.behavior.pressure_plate.missing_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.missing_next_block: "在文件 发现问题 - 方块 '' 的 'change_over_time_block' 行为缺少必需的 'next-block' 配置项" +warning.config.block.behavior.wall_attached.missing_facing: "在文件 发现问题 - 方块 '' 的 'wall_attached_block' 行为缺少必需的 'facing' 属性" 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/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java index cdc2ddd82..2cb96abb7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java @@ -48,4 +48,23 @@ public class BlockPlaceContext extends UseOnContext { public Direction getNearestLookingDirection() { return Direction.orderedByNearest(this.getPlayer())[0]; } + + public Direction[] getNearestLookingDirections() { + Direction[] directions = Direction.orderedByNearest(this.getPlayer()); + if (!this.replaceClicked) { + Direction clickedFace = this.getClickedFace(); + int i = 0; + + while (i < directions.length && directions[i] != clickedFace.opposite()) { + i++; + } + + if (i > 0) { + System.arraycopy(directions, 0, directions, 1, i); + directions[0] = clickedFace.opposite(); + } + + } + return directions; + } } diff --git a/gradle.properties b/gradle.properties index 025ef70a7..6cacafa74 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.62.19 config_version=45 -lang_version=27 +lang_version=28 project_group=net.momirealms latest_supported_version=1.21.8