9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-30 12:29:15 +00:00

初步实现台阶

This commit is contained in:
XiaoMoMi
2025-06-21 04:41:05 +08:00
parent 56d797f59f
commit 16fea80479
19 changed files with 435 additions and 51 deletions

View File

@@ -23,6 +23,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key STACKABLE_BLOCK = Key.from("craftengine:stackable_block");
public static final Key STURDY_BASE_BLOCK = Key.from("craftengine:sturdy_base_block");
public static final Key FENCE_GATE_BLOCK = Key.from("craftengine:fence_gate_block");
public static final Key SLAB_BLOCK = Key.from("craftengine:slab_block");
public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -44,5 +46,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(STACKABLE_BLOCK, StackableBlockBehavior.FACTORY);
register(STURDY_BASE_BLOCK, SturdyBaseBlockBehavior.FACTORY);
register(FENCE_GATE_BLOCK, FenceGateBlockBehavior.FACTORY);
register(SLAB_BLOCK, SlabBlockBehavior.FACTORY);
register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY);
}
}

View File

@@ -0,0 +1,127 @@
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.MFluids;
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.Property;
import net.momirealms.craftengine.core.block.state.properties.SlabType;
import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.BlockBoundItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.inventory.ItemStack;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
public class SlabBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<SlabType> typeProperty;
public SlabBlockBehavior(CustomBlock block, Property<SlabType> typeProperty) {
super(block);
this.typeProperty = typeProperty;
}
@SuppressWarnings("unchecked")
@Override
public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) {
SlabType type = state.get(this.typeProperty);
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
if (type == SlabType.DOUBLE) return false;
Optional<CustomItem<ItemStack>> itemInHand = item.getCustomItem();
if (itemInHand.isEmpty()) return false;
CustomItem<ItemStack> customItem = itemInHand.get();
Key blockId = null;
for (ItemBehavior itemBehavior : customItem.behaviors()) {
if (itemBehavior instanceof BlockBoundItemBehavior behavior) {
blockId = behavior.block();
}
}
if (blockId == null || !blockId.equals(super.customBlock.id())) return false;
if (!context.replacingClickedOnBlock()) return true;
boolean upper = context.getClickLocation().y - (double) context.getClickedPos().y() > (double) 0.5F;
Direction clickedFace = context.getClickedFace();
return type == SlabType.BOTTOM ?
clickedFace == Direction.UP || upper && clickedFace.axis().isHorizontal() :
clickedFace == Direction.DOWN || !upper && clickedFace.axis().isHorizontal();
}
@Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
BlockPos clickedPos = context.getClickedPos();
ImmutableBlockState blockState = context.getLevel().getBlockAt(clickedPos).customBlockState();
if (blockState != null && blockState.owner().value() == super.customBlock) {
return blockState.with(this.typeProperty, SlabType.DOUBLE).with(super.waterloggedProperty, false);
} else {
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
state = state.with(super.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);
Direction clickedFace = context.getClickedFace();
return clickedFace == Direction.DOWN || clickedFace != Direction.UP && context.getClickLocation().y - (double) clickedPos.y() > (double) 0.5F ? state.with(this.typeProperty, SlabType.TOP) : state.with(this.typeProperty, SlabType.BOTTOM);
}
}
@Override
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object blockState = args[2];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState == null || immutableBlockState.isEmpty()) return false;
return immutableBlockState.get(this.typeProperty) != SlabType.DOUBLE && super.placeLiquid(thisBlock, args, superMethod);
}
@Override
public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object blockState = VersionHelper.isOrAbove1_20_2() ? args[3] : args[2];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState == null || immutableBlockState.isEmpty()) return false;
return immutableBlockState.get(this.typeProperty) != SlabType.DOUBLE && super.canPlaceLiquid(thisBlock, args, superMethod);
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object blockState = args[0];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
if (immutableBlockState.get(super.waterloggedProperty)) {
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5);
}
return blockState;
}
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
Object blockState = args[0];
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (state == null || state.isEmpty()) return false;
if (type == CoreReflections.instance$PathComputationType$WATER) {
return state.get(this.typeProperty) != SlabType.DOUBLE && state.get(super.waterloggedProperty);
}
return false;
}
public static class Factory implements BlockBehaviorFactory {
@SuppressWarnings("unchecked")
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<SlabType> type = (Property<SlabType>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("type"), "warning.config.block.behavior.trapdoor.missing_type");
return new SlabBlockBehavior(block, type);
}
}
}

View File

@@ -0,0 +1,23 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import java.util.Map;
public class StairsBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
public StairsBlockBehavior(CustomBlock block) {
super(block);
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
return new StairsBlockBehavior(block);
}
}
}

View File

@@ -42,6 +42,17 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
return super.useOnBlock(context, state);
}
@Override
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
for (AbstractBlockBehavior behavior : this.behaviors) {
InteractionResult result = behavior.useWithoutItem(context, state);
if (result != InteractionResult.PASS) {
return result;
}
}
return super.useWithoutItem(context, state);
}
@Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
for (AbstractBlockBehavior behavior : this.behaviors) {
@@ -189,4 +200,14 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
behavior.setPlacedBy(context, state);
}
}
@Override
public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) {
for (AbstractBlockBehavior behavior : this.behaviors) {
if (!behavior.canBeReplaced(context, state)) {
return false;
}
}
return super.canBeReplaced(context, state);
}
}

View File

@@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.behavior.BlockBoundItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
@@ -52,7 +53,7 @@ import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
public class BlockItemBehavior extends ItemBehavior {
public class BlockItemBehavior extends BlockBoundItemBehavior {
public static final Factory FACTORY = new Factory();
private final Key blockId;
@@ -196,7 +197,8 @@ public class BlockItemBehavior extends ItemBehavior {
}
}
public Key blockId() {
@Override
public Key block() {
return this.blockId;
}

View File

@@ -30,25 +30,11 @@ public class BukkitBlockInWorld implements BlockInWorld {
this.block = block;
}
@SuppressWarnings("unchecked")
@Override
public boolean canBeReplaced(BlockPlaceContext context) {
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(this.block.getBlockData()));
if (customState != null && !customState.isEmpty()) {
Key clickedBlockId = customState.owner().value().id();
Item<ItemStack> item = (Item<ItemStack>) context.getPlayer().getItemInHand(context.getHand());
Optional<CustomItem<ItemStack>> customItem = BukkitItemManager.instance().getCustomItem(item.id());
if (customItem.isPresent()) {
CustomItem<ItemStack> custom = customItem.get();
for (ItemBehavior behavior : custom.behaviors()) {
if (behavior instanceof BlockItemBehavior blockItemBehavior) {
Key blockId = blockItemBehavior.blockId();
if (blockId.equals(clickedBlockId)) {
return false;
}
}
}
}
return customState.behavior().canBeReplaced(context, customState);
}
return this.block.isReplaceable();
}