9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2026-01-04 15:41:38 +00:00

Merge pull request #383 from jhqwqmc/dev

feat(block): 添加栅栏方块行为
This commit is contained in:
XiaoMoMi
2025-09-19 01:41:25 +08:00
committed by GitHub
14 changed files with 390 additions and 22 deletions

View File

@@ -36,6 +36,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key LIQUID_FLOWABLE_BLOCK = Key.from("craftengine:liquid_flowable_block");
public static final Key SIMPLE_PARTICLE_BLOCK = Key.from("craftengine:simple_particle_block");
public static final Key WALL_TORCH_PARTICLE_BLOCK = Key.from("craftengine:wall_torch_particle_block");
public static final Key FENCE_BLOCK = Key.from("craftengine:fence_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -70,5 +71,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(LIQUID_FLOWABLE_BLOCK, LiquidFlowableBlockBehavior.FACTORY);
register(SIMPLE_PARTICLE_BLOCK, SimpleParticleBlockBehavior.FACTORY);
register(WALL_TORCH_PARTICLE_BLOCK, WallTorchParticleBlockBehavior.FACTORY);
register(FENCE_BLOCK, FenceBlockBehavior.FACTORY);
}
}

View File

@@ -4,6 +4,7 @@ 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.BlockTags;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.block.BlockBehavior;
@@ -13,24 +14,41 @@ 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.plugin.locale.LocalizedResourceConfigException;
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.util.*;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.World;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import java.util.Map;
import java.util.*;
import java.util.concurrent.Callable;
public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior {
public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<?> facingProperty;
private final boolean isSixDirection;
private final List<Object> tagsCanSurviveOn;
private final Set<Object> blockStatesCanSurviveOn;
private final Set<String> customBlocksCansSurviveOn;
private final boolean blacklistMode;
public DirectionalAttachedBlockBehavior(CustomBlock customBlock, Property<?> facingProperty, boolean isSixDirection) {
super(customBlock);
public DirectionalAttachedBlockBehavior(CustomBlock customBlock,
Property<?> facingProperty,
boolean isSixDirection,
int delay,
boolean blacklist,
List<Object> tagsCanSurviveOn,
Set<Object> blockStatesCanSurviveOn,
Set<String> customBlocksCansSurviveOn) {
super(customBlock, delay);
this.facingProperty = facingProperty;
this.isSixDirection = isSixDirection;
this.tagsCanSurviveOn = tagsCanSurviveOn;
this.blockStatesCanSurviveOn = blockStatesCanSurviveOn;
this.customBlocksCansSurviveOn = customBlocksCansSurviveOn;
this.blacklistMode = blacklist;
}
@Override
@@ -51,8 +69,8 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior {
}
@Override
public boolean canSurvive(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null);
protected boolean canSurvive(Object thisBlock, Object blockState, Object world, Object pos) throws Exception {
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null);
if (state == null) return false;
DirectionalAttachedBlockBehavior behavior = state.behavior().getAs(DirectionalAttachedBlockBehavior.class).orElse(null);
if (behavior == null) return false;
@@ -62,10 +80,34 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior {
} else {
direction = ((HorizontalDirection) state.get(behavior.facingProperty)).opposite().toDirection();
}
BlockPos blockPos = LocationUtils.fromBlockPos(args[2]).relative(direction);
BlockPos blockPos = LocationUtils.fromBlockPos(pos).relative(direction);
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), CoreReflections.instance$SupportType$FULL);
Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, nmsPos);
return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, world, nmsPos, DirectionUtils.toNMSDirection(direction), CoreReflections.instance$SupportType$FULL)
&& mayPlaceOn(nmsState);
}
private boolean mayPlaceOn(Object state) {
for (Object tag : this.tagsCanSurviveOn) {
if (FastNMS.INSTANCE.method$BlockStateBase$is(state, tag)) {
return !this.blacklistMode;
}
}
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
if (optionalCustomState.isEmpty()) {
if (!this.blockStatesCanSurviveOn.isEmpty() && this.blockStatesCanSurviveOn.contains(state)) {
return !this.blacklistMode;
}
} else {
ImmutableBlockState belowCustomState = optionalCustomState.get();
if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) {
return !this.blacklistMode;
}
if (this.customBlocksCansSurviveOn.contains(belowCustomState.toString())) {
return !this.blacklistMode;
}
}
return this.blacklistMode;
}
@SuppressWarnings("unchecked")
@@ -101,7 +143,37 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior {
if (!(isHorizontalDirection || isDirection)) {
throw new LocalizedResourceConfigException("warning.config.block.behavior.surface_attached.missing_facing");
}
return new DirectionalAttachedBlockBehavior(block, facing, isDirection);
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments);
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", true), "blacklist");
return new DirectionalAttachedBlockBehavior(block, facing, isDirection, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right());
}
}
@SuppressWarnings("DuplicatedCode")
private static Tuple<List<Object>, Set<Object>, Set<String>> readTagsAndState(Map<String, Object> arguments) {
List<Object> mcTags = new ArrayList<>();
for (String tag : MiscUtils.getAsStringList(arguments.getOrDefault("attached-block-tags", List.of()))) {
mcTags.add(BlockTags.getOrCreate(Key.of(tag)));
}
Set<Object> mcBlocks = new HashSet<>();
Set<String> customBlocks = new HashSet<>();
for (String blockStateStr : MiscUtils.getAsStringList(arguments.getOrDefault("attached-blocks", List.of()))) {
int index = blockStateStr.indexOf('[');
Key blockType = index != -1 ? Key.from(blockStateStr.substring(0, index)) : Key.from(blockStateStr);
Material material = Registry.MATERIAL.get(new NamespacedKey(blockType.namespace(), blockType.value()));
if (material != null) {
if (index == -1) {
// vanilla
mcBlocks.addAll(BlockStateUtils.getAllVanillaBlockStates(blockType));
} else {
mcBlocks.add(BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(blockStateStr)));
}
} else {
// custom maybe
customBlocks.add(blockStateStr);
}
}
return new Tuple<>(mcTags, mcBlocks, customBlocks);
}
}

View File

@@ -0,0 +1,150 @@
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.MFluids;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MTagKeys;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.BooleanProperty;
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.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.HorizontalDirection;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.World;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
public class FenceBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final BooleanProperty northProperty;
private final BooleanProperty eastProperty;
private final BooleanProperty southProperty;
private final BooleanProperty westProperty;
private final Object connectableBlockTag;
private final boolean canLeash;
public FenceBlockBehavior(CustomBlock customBlock,
BooleanProperty northProperty,
BooleanProperty eastProperty,
BooleanProperty southProperty,
BooleanProperty westProperty,
Object connectableBlockTag,
boolean canLeash) {
super(customBlock);
this.northProperty = northProperty;
this.eastProperty = eastProperty;
this.southProperty = southProperty;
this.westProperty = westProperty;
this.connectableBlockTag = connectableBlockTag;
this.canLeash = canLeash;
}
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
return false;
}
public boolean connectsTo(BlockStateWrapper state, boolean isSideSolid, HorizontalDirection direction) {
boolean isSameFence = this.isSameFence(state);
boolean flag = CoreReflections.clazz$FenceGateBlock.isInstance(BlockStateUtils.getBlockOwner(state.literalObject()))
? FastNMS.INSTANCE.method$FenceGateBlock$connectsToDirection(state.literalObject(), DirectionUtils.toNMSDirection(direction.toDirection()))
: FenceGateBlockBehavior.connectsToDirection(state, direction);
return !BlockUtils.isExceptionForConnection(state) && isSideSolid || isSameFence || flag;
}
private boolean isSameFence(BlockStateWrapper state) {
Object blockState = state.literalObject();
return FastNMS.INSTANCE.method$BlockStateBase$is(blockState, MTagKeys.Block$FENCES)
&& FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.connectableBlockTag)
== FastNMS.INSTANCE.method$BlockStateBase$is(this.customBlock.defaultState().customBlockState().literalObject(), this.connectableBlockTag);
}
@Override
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
if (!this.canLeash) return InteractionResult.PASS;
Player player = context.getPlayer();
if (player == null) return InteractionResult.PASS;
if (FastNMS.INSTANCE.method$LeadItem$bindPlayerMobs(player.serverPlayer(), context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()))) {
player.swingHand(InteractionHand.MAIN_HAND);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
@Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
World level = context.getLevel();
BlockPos clickedPos = context.getClickedPos();
Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(level.serverWorld(), LocationUtils.toBlockPos(clickedPos));
BlockPos blockPos = clickedPos.north();
BlockPos blockPos1 = clickedPos.east();
BlockPos blockPos2 = clickedPos.south();
BlockPos blockPos3 = clickedPos.west();
BlockStateWrapper blockState = level.getBlockAt(blockPos).blockState();
BlockStateWrapper blockState1 = level.getBlockAt(blockPos1).blockState();
BlockStateWrapper blockState2 = level.getBlockAt(blockPos2).blockState();
BlockStateWrapper blockState3 = level.getBlockAt(blockPos3).blockState();
BooleanProperty waterlogged = (BooleanProperty) state.owner().value().getProperty("waterlogged");
if (waterlogged != null) {
state = state.with(waterlogged, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);
}
return state
.with(this.northProperty, this.connectsTo(blockState, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos), CoreReflections.instance$Direction$SOUTH, CoreReflections.instance$SupportType$FULL), HorizontalDirection.SOUTH))
.with(this.eastProperty, this.connectsTo(blockState1, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState1.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos1), CoreReflections.instance$Direction$WEST, CoreReflections.instance$SupportType$FULL), HorizontalDirection.WEST))
.with(this.southProperty, this.connectsTo(blockState2, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState2.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos2), CoreReflections.instance$Direction$NORTH, CoreReflections.instance$SupportType$FULL), HorizontalDirection.NORTH))
.with(this.westProperty, this.connectsTo(blockState3, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState3.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos3), CoreReflections.instance$Direction$EAST, CoreReflections.instance$SupportType$FULL), HorizontalDirection.EAST));
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Optional<ImmutableBlockState> optionalState = BlockStateUtils.getOptionalCustomBlockState(args[0]);
BooleanProperty waterlogged = (BooleanProperty) optionalState
.map(BlockStateHolder::owner)
.map(Holder::value)
.map(block -> block.getProperty("waterlogged"))
.orElse(null);
if (waterlogged != null) {
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
}
if (DirectionUtils.fromNMSDirection(args[updateShape$direction]).axis().isHorizontal() && optionalState.isPresent()) {
Direction direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]);
ImmutableBlockState state = optionalState.get();
if (state.owner() != null) {
BooleanProperty booleanProperty = (BooleanProperty) state.owner().value().getProperty(direction.name().toLowerCase(Locale.ROOT));
if (booleanProperty != null) {
BlockStateWrapper wrapper = BlockStateUtils.toBlockStateWrapper(args[updateShape$neighborState]);
return state.with(booleanProperty, this.connectsTo(wrapper, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(wrapper.literalObject(), args[updateShape$level], args[5], DirectionUtils.toNMSDirection(direction.opposite()), CoreReflections.instance$SupportType$FULL), direction.opposite().toHorizontalDirection())).customBlockState().literalObject();
}
}
}
return superMethod.call();
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
BooleanProperty north = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("north"), "warning.config.block.behavior.fence.missing_north");
BooleanProperty east = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("east"), "warning.config.block.behavior.fence.missing_east");
BooleanProperty south = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("south"), "warning.config.block.behavior.fence.missing_south");
BooleanProperty west = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("west"), "warning.config.block.behavior.fence.missing_west");
Object connectableBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("connectable-block-tag", "minecraft:wooden_fences").toString())));
connectableBlockTag = connectableBlockTag != null ? connectableBlockTag : MTagKeys.Block$WOODEN_FENCES;
boolean canLeash = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-leash", false), "can-leash");
return new FenceBlockBehavior(block, north, east, south, west, connectableBlockTag, canLeash);
}
}
}

View File

@@ -10,10 +10,7 @@ import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.bukkit.util.InteractUtils;
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.*;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
@@ -262,6 +259,22 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
}
}
public static boolean connectsToDirection(BlockStateWrapper state, HorizontalDirection direction) {
FenceGateBlockBehavior fence = BlockStateUtils.getOptionalCustomBlockState(state.literalObject())
.map(ImmutableBlockState::behavior)
.flatMap(behavior -> behavior.getAs(FenceGateBlockBehavior.class))
.orElse(null);
if (fence == null) return false;
Direction facing = null;
ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state.literalObject()).orElse(null);
if (customState == null) return false;
Property<?> facingProperty = customState.owner().value().getProperty("facing");
if (facingProperty != null && facingProperty.valueClass() == HorizontalDirection.class) {
facing = ((HorizontalDirection) customState.get(facingProperty)).toDirection();
}
return facing != null && facing.axis() == direction.toDirection().clockWise().axis();
}
public static class Factory implements BlockBehaviorFactory {
@Override

View File

@@ -4393,4 +4393,11 @@ public final class CoreReflections {
public static final Constructor<?> constructor$AdvancementHolder = Optional.ofNullable(clazz$AdvancementHolder)
.map(it -> ReflectionUtils.getConstructor(it, clazz$ResourceLocation, clazz$Advancement))
.orElse(null);
public static final Class<?> clazz$FenceGateBlock = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.level.block.BlockFenceGate",
"world.level.block.FenceGateBlock"
)
);
}

View File

@@ -22,6 +22,11 @@ public final class MBlocks {
public static final Object WATER$defaultState;
public static final Object TNT;
public static final Object TNT$defaultState;
public static final Object BARRIER;
public static final Object CARVED_PUMPKIN;
public static final Object JACK_O_LANTERN;
public static final Object MELON;
public static final Object PUMPKIN;
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
@@ -45,5 +50,10 @@ public final class MBlocks {
WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER);
TNT = getById("tnt");
TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT);
BARRIER = getById("barrier");
CARVED_PUMPKIN = getById("carved_pumpkin");
JACK_O_LANTERN = getById("jack_o_lantern");
MELON = getById("melon");
PUMPKIN = getById("pumpkin");
}
}

View File

@@ -9,6 +9,9 @@ public final class MTagKeys {
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");
private static Object create(Object registry, String location) {
Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location);

View File

@@ -45,8 +45,12 @@ public final class BlockStateUtils {
public static BlockStateWrapper toBlockStateWrapper(BlockData blockData) {
Object state = blockDataToBlockState(blockData);
int id = blockStateToId(state);
return new BukkitBlockStateWrapper(state, id);
return toBlockStateWrapper(state);
}
public static BlockStateWrapper toBlockStateWrapper(Object blockState) {
int id = blockStateToId(blockState);
return new BukkitBlockStateWrapper(blockState, id);
}
public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item<ItemStack> itemInHand) {

View File

@@ -0,0 +1,22 @@
package net.momirealms.craftengine.bukkit.util;
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.BlockStateWrapper;
public final class BlockUtils {
private BlockUtils() {}
public static boolean isExceptionForConnection(BlockStateWrapper state) {
Object blockState = state.literalObject();
return CoreReflections.clazz$LeavesBlock.isInstance(BlockStateUtils.getBlockOwner(blockState))
|| FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.BARRIER)
|| FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.CARVED_PUMPKIN)
|| FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.JACK_O_LANTERN)
|| FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.MELON)
|| FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.PUMPKIN)
|| FastNMS.INSTANCE.method$BlockStateBase$is(blockState, MTagKeys.Block$SHULKER_BOXES);
}
}

View File

@@ -321,6 +321,10 @@ warning.config.block.behavior.double_high.missing_half: "<yellow>Issue found in
warning.config.block.behavior.change_over_time.missing_next_block: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'next_block' argument for 'change_over_time_block' behavior.</yellow>"
warning.config.block.behavior.surface_attached.missing_facing: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'facing' property for 'surface_attached_block' behavior.</yellow>"
warning.config.block.behavior.wall_torch_particle.missing_facing: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'facing' property for 'wall_torch_particle_block' behavior.</yellow>"
warning.config.block.behavior.fence.missing_north: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'north' property for 'fence_block' behavior.</yellow>"
warning.config.block.behavior.fence.missing_east: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'east' property for 'fence_block' behavior.</yellow>"
warning.config.block.behavior.fence.missing_south: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'south' property for 'fence_block' behavior.</yellow>"
warning.config.block.behavior.fence.missing_west: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'west' property for 'fence_block' behavior.</yellow>"
warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>"
warning.config.model.generation.conflict: "<yellow>Issue found in file <arg:0> - Failed to generate model for '<arg:1>' as two or more configurations attempt to generate different json models with the same path: '<arg:2>'.</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid display position '<arg:2>' in 'generation.display' section. Allowed display positions: [<arg:3>]</yellow>"

View File

@@ -315,6 +315,10 @@ warning.config.block.behavior.double_high.missing_half: "<yellow>在文件 <arg:
warning.config.block.behavior.change_over_time.missing_next_block: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'change_over_time_block' 行为缺少必需的 'next-block' 参数</yellow>"
warning.config.block.behavior.surface_attached.missing_facing: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'surface_attached_block' 行为缺少必需的 'facing' 属性</yellow>"
warning.config.block.behavior.wall_torch_particle.missing_facing: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'wall_torch_particle_block' 行为缺少必需的 'facing' 属性</yellow>"
warning.config.block.behavior.fence.missing_north: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_block' 行为缺少必需的 'north' 属性</yellow>"
warning.config.block.behavior.fence.missing_east: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_block' 行为缺少必需的 'east' 属性</yellow>"
warning.config.block.behavior.fence.missing_south: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_block' 行为缺少必需的 'south' 属性</yellow>"
warning.config.block.behavior.fence.missing_west: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'fence_block' 行为缺少必需的 'west' 属性</yellow>"
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>"
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>"

View File

@@ -55,4 +55,48 @@ public class BlockPos extends Vec3i {
public BlockPos offset(int x, int y, int z) {
return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.x() + x, this.y() + y, this.z() + z);
}
public BlockPos immutable() {
return this;
}
@Override
public BlockPos north() {
return new BlockPos(this.x(), this.y(), this.z() - 1);
}
@Override
public BlockPos north(int distance) {
return distance == 0 ? this.immutable() : new BlockPos(this.x(), this.y(), this.z() - distance);
}
@Override
public BlockPos south() {
return new BlockPos(this.x(), this.y(), this.z() + 1);
}
@Override
public BlockPos south(int distance) {
return distance == 0 ? this.immutable() : new BlockPos(this.x(), this.y(), this.z() + distance);
}
@Override
public BlockPos west() {
return new BlockPos(this.x() - 1, this.y(), this.z());
}
@Override
public BlockPos west(int distance) {
return distance == 0 ? this.immutable() : new BlockPos(this.x() - distance, this.y(), this.z());
}
@Override
public BlockPos east() {
return new BlockPos(this.x() + 1, this.y(), this.z());
}
@Override
public BlockPos east(int distance) {
return distance == 0 ? this.immutable() : new BlockPos(this.x() + distance, this.y(), this.z());
}
}

View File

@@ -92,4 +92,37 @@ public class Vec3i implements Comparable<Vec3i> {
return this.y() - vec3i.y();
}
}
public Vec3i north() {
return this.north(1);
}
public Vec3i north(int distance) {
return this.relative(Direction.NORTH, distance);
}
public Vec3i south() {
return this.south(1);
}
public Vec3i south(int distance) {
return this.relative(Direction.SOUTH, distance);
}
public Vec3i west() {
return this.west(1);
}
public Vec3i west(int distance) {
return this.relative(Direction.WEST, distance);
}
public Vec3i east() {
return this.east(1);
}
public Vec3i east(int distance) {
return this.relative(Direction.EAST, distance);
}
}

View File

@@ -3,8 +3,8 @@ org.gradle.jvmargs=-Xmx1G
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.63.3
config_version=45
lang_version=29
config_version=46
lang_version=30
project_group=net.momirealms
latest_supported_version=1.21.8
@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.5
anti_grief_version=0.20
nms_helper_version=1.0.90
nms_helper_version=1.0.91
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.33.1