9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-26 02:19:23 +00:00

初步完成门行为

This commit is contained in:
XiaoMoMi
2025-06-18 00:07:19 +08:00
parent 9f5cf4a5ae
commit 0990ac4817
16 changed files with 311 additions and 25 deletions

View File

@@ -62,7 +62,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
}
@Override
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object world = args[1];
Object blockPos = args[2];
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2);

View File

@@ -20,6 +20,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key GRASS_BLOCK = Key.from("craftengine:grass_block");
public static final Key LAMP_BLOCK = Key.from("craftengine:lamp_block");
public static final Key TRAPDOOR_BLOCK = Key.from("craftengine:trapdoor_block");
public static final Key DOOR_BLOCK = Key.from("craftengine:door_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -38,5 +39,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(GRASS_BLOCK, GrassBlockBehavior.FACTORY);
register(LAMP_BLOCK, LampBlockBehavior.FACTORY);
register(TRAPDOOR_BLOCK, TrapDoorBlockBehavior.FACTORY);
register(DOOR_BLOCK, DoorBlockBehavior.FACTORY);
}
}

View File

@@ -59,6 +59,7 @@ public class ConcretePowderBlockBehavior extends BukkitBlockBehavior {
return this.defaultBlockState;
}
@SuppressWarnings("UnstableApiUsage")
@Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
Object level = context.getLevel().serverWorld();

View File

@@ -0,0 +1,256 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
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.MFluids;
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.bukkit.world.BukkitWorld;
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.block.properties.Property;
import net.momirealms.craftengine.core.block.state.properties.DoorHinge;
import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf;
import net.momirealms.craftengine.core.block.state.properties.SingleBlockHalf;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import org.bukkit.Bukkit;
import org.bukkit.GameEvent;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Door;
import org.bukkit.entity.Entity;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.util.Vector;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
public class DoorBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<DoubleBlockHalf> halfProperty;
private final Property<HorizontalDirection> facingProperty;
private final Property<DoorHinge> hingeProperty;
private final Property<Boolean> poweredProperty;
private final Property<Boolean> openProperty;
private final boolean canOpenWithHand;
private final boolean canOpenByWindCharge;
public DoorBlockBehavior(CustomBlock block,
Property<DoubleBlockHalf> halfProperty,
Property<HorizontalDirection> facingProperty,
Property<DoorHinge> hingeProperty,
Property<Boolean> poweredProperty,
Property<Boolean> openProperty,
boolean canOpenWithHand,
boolean canOpenByWindCharge) {
super(block);
this.halfProperty = halfProperty;
this.facingProperty = facingProperty;
this.hingeProperty = hingeProperty;
this.poweredProperty = poweredProperty;
this.openProperty = openProperty;
this.canOpenWithHand = canOpenWithHand;
this.canOpenByWindCharge = canOpenByWindCharge;
}
public boolean isOpen(ImmutableBlockState state) {
return state.get(this.openProperty);
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object blockState = args[0];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
DoubleBlockHalf half = immutableBlockState.get(this.halfProperty);
Object direction = VersionHelper.isOrAbove1_21_2() ? args[4] : args[0];
if (DirectionUtils.isYAxis(direction) && half == DoubleBlockHalf.LOWER == (direction == CoreReflections.instance$Direction$UP)) {
ImmutableBlockState neighborState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(VersionHelper.isOrAbove1_21_2() ? args[6] : args[2]));
if (neighborState == null || neighborState.isEmpty()) {
return MBlocks.AIR$defaultState;
}
Optional<DoorBlockBehavior> anotherDoorBehavior = neighborState.behavior().getAs(DoorBlockBehavior.class);
if (anotherDoorBehavior.isEmpty()) {
return MBlocks.AIR$defaultState;
}
if (neighborState.get(anotherDoorBehavior.get().halfProperty) != half) {
return neighborState.with(anotherDoorBehavior.get().halfProperty, half);
}
return MBlocks.AIR$defaultState;
} else {
return half == DoubleBlockHalf.LOWER &&
direction == CoreReflections.instance$Direction$DOWN &&
!FastNMS.INSTANCE.method$BlockStateBase$canSurvive(blockState, VersionHelper.isOrAbove1_21_2() ? args[1] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[2]) ? MBlocks.AIR$defaultState : blockState;
}
}
@Override
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
if (state == null || state.isEmpty()) return;
if (state.get(this.poweredProperty)) return;
if (state.get(this.halfProperty) == DoubleBlockHalf.LOWER) {
this.setOpen(null, args[1], state, LocationUtils.fromBlockPos(args[2]), !this.isOpen(state));
}
}
}
@Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
World world = context.getLevel();
Object level = world.serverWorld();
BlockPos pos = context.getClickedPos();
if (pos.y() < context.getLevel().worldHeight().getMaxBuildHeight() && world.getBlockAt(pos.above()).canBeReplaced(context)) {
boolean hasSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, LocationUtils.toBlockPos(pos)) || FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, LocationUtils.toBlockPos(pos.above()));
return state.with(this.poweredProperty, hasSignal)
.with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection())
.with(this.openProperty, hasSignal)
.with(this.halfProperty, DoubleBlockHalf.LOWER)
.with(this.hingeProperty, getHinge(context));
}
return null;
}
private DoorHinge getHinge(BlockPlaceContext context) {
Object serverLevel = context.getLevel().serverWorld();
BlockPos clickedPos = context.getClickedPos();
Direction horizontalDirection = context.getHorizontalDirection();
BlockPos blockPos = clickedPos.above();
Direction counterClockWise = horizontalDirection.counterClockWise();
Object blockPos1 = LocationUtils.toBlockPos(clickedPos.relative(counterClockWise));
Object blockState1 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, blockPos1);
Object blockPos2 = LocationUtils.toBlockPos(blockPos.relative(counterClockWise));
Object blockState2 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, blockPos2);
Direction clockWise = horizontalDirection.clockWise();
Object blockPos3 = LocationUtils.toBlockPos(clickedPos.relative(clockWise));
Object blockState3 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, blockPos3);
Object blockPos4 = LocationUtils.toBlockPos(blockPos.relative(clockWise));
Object blockState4 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, blockPos4);
int i = (FastNMS.INSTANCE.method$BlockStateBase$isCollisionShapeFullBlock(blockState1, serverLevel, blockPos1) ? -1 : 0) +
(FastNMS.INSTANCE.method$BlockStateBase$isCollisionShapeFullBlock(blockState2, serverLevel, blockPos2) ? -1 : 0) +
(FastNMS.INSTANCE.method$BlockStateBase$isCollisionShapeFullBlock(blockState3, serverLevel, blockPos3) ? 1 : 0) +
(FastNMS.INSTANCE.method$BlockStateBase$isCollisionShapeFullBlock(blockState4, serverLevel, blockPos4) ? 1 : 0);
boolean anotherDoor1 = isAnotherDoor(blockState1);
boolean anotherDoor2 = isAnotherDoor(blockState3);
if ((!anotherDoor1 || anotherDoor2) && i <= 0) {
if ((!anotherDoor2 || anotherDoor1) && i == 0) {
int stepX = horizontalDirection.stepX();
int stepZ = horizontalDirection.stepZ();
Vec3d clickLocation = context.getClickLocation();
double d = clickLocation.x - (double) clickedPos.x();
double d1 = clickLocation.z - (double) clickedPos.z();
return stepX < 0 && d1 < (double) 0.5F || stepX > 0 && d1 > (double) 0.5F || stepZ < 0 && d > (double) 0.5F || stepZ > 0 && d < (double) 0.5F ? DoorHinge.RIGHT : DoorHinge.LEFT;
} else {
return DoorHinge.LEFT;
}
} else {
return DoorHinge.RIGHT;
}
}
private boolean isAnotherDoor(Object blockState) {
int id = BlockStateUtils.blockStateToId(blockState);
if (BlockStateUtils.isVanillaBlock(id)) {
BlockData blockData = BlockStateUtils.fromBlockData(blockState);
return blockData instanceof Door door && door.getHalf() == Bisected.Half.BOTTOM;
} else {
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id);
if (state.isEmpty()) return false;
Optional<DoorBlockBehavior> optional = state.behavior().getAs(DoorBlockBehavior.class);
return optional.isPresent() && state.get(optional.get().halfProperty) == DoubleBlockHalf.LOWER;
}
}
public void setOpen(@Nullable Player player, Object serverLevel, ImmutableBlockState state, BlockPos pos, boolean isOpen) {
if (isOpen(state) != isOpen) {
FastNMS.INSTANCE.method$LevelWriter$setBlock(serverLevel, LocationUtils.toBlockPos(pos), state.with(this.openProperty, isOpen).customBlockState().handle(), UpdateOption.builder().updateImmediate().updateClients().build().flags());
FastNMS.INSTANCE.method$Level$getCraftWorld(serverLevel).sendGameEvent(player == null ? null : (org.bukkit.entity.Player) player.platformPlayer(), isOpen ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(pos.x(), pos.y(), pos.z()));
// todo 播放声音
}
}
@Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
if (!this.canOpenWithHand) {
return InteractionResult.PASS;
}
setOpen(context.getPlayer(), context.getLevel().serverWorld(), state, context.getClickedPos(), !state.get(this.openProperty));
return InteractionResult.SUCCESS;
}
@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$LAND || type == CoreReflections.instance$PathComputationType$AIR) {
return state.get(this.openProperty);
}
return false;
}
@SuppressWarnings("UnstableApiUsage")
@Override
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object blockPos = args[2];
Object level = args[1];
Object blockState = args[0];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
Object anotherHalfPos = immutableBlockState.get(this.halfProperty) == DoubleBlockHalf.LOWER ? LocationUtils.above(blockPos) : LocationUtils.below(blockPos);
Block bukkitBlock = FastNMS.INSTANCE.method$CraftBlock$at(level, blockPos);
Block anotherBukkitBlock = FastNMS.INSTANCE.method$CraftBlock$at(level, anotherHalfPos);
int power = Math.max(bukkitBlock.getBlockPower(), anotherBukkitBlock.getBlockPower());
int oldPower = immutableBlockState.get(this.poweredProperty) ? 15 : 0;
if (oldPower == 0 ^ power == 0) {
BlockRedstoneEvent event = new BlockRedstoneEvent(bukkitBlock, oldPower, power);
Bukkit.getPluginManager().callEvent(event);
boolean flag = event.getNewCurrent() > 0;
if (flag != immutableBlockState.get(this.openProperty)) {
FastNMS.INSTANCE.method$Level$getCraftWorld(level).sendGameEvent(null, flag ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()));
// todo 播放声音
}
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, immutableBlockState.with(this.poweredProperty, flag).with(this.openProperty, flag).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
}
}
@SuppressWarnings("unchecked")
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<DoubleBlockHalf> half = (Property<DoubleBlockHalf>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.door.missing_half");
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.door.missing_facing");
Property<DoorHinge> hinge = (Property<DoorHinge>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("hinge"), "warning.config.block.behavior.door.missing_hinge");
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.door.missing_open");
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.door.missing_powered");
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
return new DoorBlockBehavior(block, half, facing, hinge, powered, open, canOpenWithHand, canOpenByWindCharge);
}
}
}

View File

@@ -33,14 +33,14 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
}
@Override
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object world = args[1];
Object blockPos = args[2];
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2);
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object world;
Object blockPos;
if (VersionHelper.isOrAbove1_21_2()) {

View File

@@ -52,7 +52,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
}
@Override
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object blockState = args[0];
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (state == null || state.isEmpty()) return;

View File

@@ -15,6 +15,7 @@ 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.block.properties.Property;
import net.momirealms.craftengine.core.block.state.properties.SingleBlockHalf;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.ItemKeys;
@@ -36,8 +37,8 @@ import java.util.concurrent.Callable;
public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<Half> halfProperty;
private final Property<HorizontalDirection> directionProperty;
private final Property<SingleBlockHalf> halfProperty;
private final Property<HorizontalDirection> facingProperty;
private final Property<Boolean> poweredProperty;
private final Property<Boolean> openProperty;
private final boolean canOpenWithHand;
@@ -45,15 +46,15 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
public TrapDoorBlockBehavior(CustomBlock block,
@Nullable Property<Boolean> waterloggedProperty,
Property<Half> halfProperty,
Property<HorizontalDirection> directionProperty,
Property<SingleBlockHalf> halfProperty,
Property<HorizontalDirection> facingProperty,
Property<Boolean> poweredProperty,
Property<Boolean> openProperty,
boolean canOpenWithHand,
boolean canOpenByWindCharge) {
super(block, waterloggedProperty);
this.halfProperty = halfProperty;
this.directionProperty = directionProperty;
this.facingProperty = facingProperty;
this.poweredProperty = poweredProperty;
this.openProperty = openProperty;
this.canOpenWithHand = canOpenWithHand;
@@ -78,11 +79,11 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
Object clickedPos = LocationUtils.toBlockPos(context.getClickedPos());
Direction clickedFace = context.getClickedFace();
if (!context.replacingClickedOnBlock() && clickedFace.axis().isHorizontal()) {
state = state.with(this.directionProperty, clickedFace.toHorizontalDirection())
.with(this.halfProperty, context.getClickLocation().y - context.getClickedPos().y() > 0.5 ? Half.TOP : Half.BOTTOM);
state = state.with(this.facingProperty, clickedFace.toHorizontalDirection())
.with(this.halfProperty, context.getClickLocation().y - context.getClickedPos().y() > 0.5 ? SingleBlockHalf.TOP : SingleBlockHalf.BOTTOM);
} else {
state = state.with(this.directionProperty, context.getHorizontalDirection().opposite().toHorizontalDirection())
.with(this.halfProperty, clickedFace == Direction.UP ? Half.BOTTOM : Half.TOP);
state = state.with(this.facingProperty, context.getHorizontalDirection().opposite().toHorizontalDirection())
.with(this.halfProperty, clickedFace == Direction.UP ? SingleBlockHalf.BOTTOM : SingleBlockHalf.TOP);
}
if (FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, clickedPos)) {
state = state.with(this.poweredProperty, true);
@@ -195,13 +196,13 @@ public class TrapDoorBlockBehavior extends WaterLoggedBlockBehavior {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<Boolean> waterlogged = (Property<Boolean>) block.getProperty("waterlogged");
Property<Half> half = (Property<Half>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.trapdoor.missing_half");
Property<HorizontalDirection> direction = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("direction"), "warning.config.block.behavior.trapdoor.missing_direction");
Property<SingleBlockHalf> half = (Property<SingleBlockHalf>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.trapdoor.missing_half");
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.trapdoor.missing_facing");
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.trapdoor.missing_open");
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.trapdoor.missing_powered");
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.trapdoor.missing_powered");
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
return new TrapDoorBlockBehavior(block, waterlogged, half, direction, powered, open, canOpenWithHand, canOpenByWindCharge);
return new TrapDoorBlockBehavior(block, waterlogged, half, facing, powered, open, canOpenWithHand, canOpenByWindCharge);
}
}
}

View File

@@ -50,4 +50,8 @@ public class DirectionUtils {
throw new RuntimeException(e);
}
}
public static boolean isYAxis(Object nmsDirection) {
return nmsDirection == CoreReflections.instance$Direction$UP || nmsDirection == CoreReflections.instance$Direction$DOWN;
}
}

View File

@@ -45,6 +45,7 @@ public class UnsafeCompositeBlockBehavior extends AbstractBlockBehavior {
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
for (AbstractBlockBehavior behavior : this.behaviors) {
state = behavior.updateStateForPlacement(context, state);
if (state == null) return null;
}
return state;
}

View File

@@ -1,5 +1,8 @@
package net.momirealms.craftengine.core.block.properties;
import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf;
import net.momirealms.craftengine.core.block.state.properties.SingleBlockHalf;
import net.momirealms.craftengine.core.block.state.properties.DoorHinge;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.Holder;
@@ -16,7 +19,9 @@ public class Properties {
public static final Key AXIS = Key.of("craftengine:axis");
public static final Key HORIZONTAL_DIRECTION = Key.of("craftengine:4-direction");
public static final Key DIRECTION = Key.of("craftengine:6-direction");
public static final Key HALF = Key.of("craftengine:half");
public static final Key SINGLE_BLOCK_HALF = Key.of("craftengine:single_block_half");
public static final Key DOUBLE_BLOCK_HALF = Key.of("craftengine:double_block_half");
public static final Key HINGE = Key.of("craftengine:hinge");
static {
register(BOOLEAN, BooleanProperty.FACTORY);
@@ -25,7 +30,9 @@ public class Properties {
register(AXIS, new EnumProperty.Factory<>(Direction.Axis.class));
register(DIRECTION, new EnumProperty.Factory<>(Direction.class));
register(HORIZONTAL_DIRECTION, new EnumProperty.Factory<>(HorizontalDirection.class));
register(HALF, new EnumProperty.Factory<>(Half.class));
register(SINGLE_BLOCK_HALF, new EnumProperty.Factory<>(SingleBlockHalf.class));
register(DOUBLE_BLOCK_HALF, new EnumProperty.Factory<>(DoubleBlockHalf.class));
register(HINGE, new EnumProperty.Factory<>(DoorHinge.class));
}
public static void register(Key key, PropertyFactory factory) {

View File

@@ -0,0 +1,5 @@
package net.momirealms.craftengine.core.block.state.properties;
public enum DoorHinge {
LEFT, RIGHT
}

View File

@@ -0,0 +1,5 @@
package net.momirealms.craftengine.core.block.state.properties;
public enum DoubleBlockHalf {
UPPER, LOWER
}

View File

@@ -0,0 +1,5 @@
package net.momirealms.craftengine.core.block.state.properties;
public enum SingleBlockHalf {
TOP, BOTTOM
}

View File

@@ -1,5 +0,0 @@
package net.momirealms.craftengine.core.util;
public enum Half {
TOP, BOTTOM
}

View File

@@ -35,6 +35,10 @@ public class BlockPos extends Vec3i {
: new BlockPos(this.x() + direction.stepX() * i, this.y() + direction.stepY() * i, this.z() + direction.stepZ() * i);
}
public BlockPos above() {
return new BlockPos(this.x(), this.y() + 1, this.z());
}
public int toSectionBlockIndex() {
return (y & 15) << 8 | (z & 15) << 4 | x & 15;
}

View File

@@ -51,7 +51,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.4
anti_grief_version=0.17
nms_helper_version=0.67.24
nms_helper_version=0.67.26
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.31.23