9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00
This commit is contained in:
jhqwqmc
2025-11-18 20:39:37 +08:00
parent c02a4918e7
commit 332ebcf153
14 changed files with 129 additions and 64 deletions

View File

@@ -46,6 +46,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key SEAT_BLOCK = Key.from("craftengine:seat_block"); public static final Key SEAT_BLOCK = Key.from("craftengine:seat_block");
public static final Key SURFACE_SPREADING_BLOCK = Key.from("craftengine:surface_spreading_block"); public static final Key SURFACE_SPREADING_BLOCK = Key.from("craftengine:surface_spreading_block");
public static final Key SNOWY_BLOCK = Key.from("craftengine:snowy_block"); public static final Key SNOWY_BLOCK = Key.from("craftengine:snowy_block");
public static final Key HANGABLE_BLOCK = Key.from("craftengine:hangable_block");
public static void init() { public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -90,5 +91,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(SEAT_BLOCK, SeatBlockBehavior.FACTORY); register(SEAT_BLOCK, SeatBlockBehavior.FACTORY);
register(SURFACE_SPREADING_BLOCK, SurfaceSpreadingBlockBehavior.FACTORY); register(SURFACE_SPREADING_BLOCK, SurfaceSpreadingBlockBehavior.FACTORY);
register(SNOWY_BLOCK, SnowyBlockBehavior.FACTORY); register(SNOWY_BLOCK, SnowyBlockBehavior.FACTORY);
register(HANGABLE_BLOCK, HangableBlockBehavior.FACTORY);
} }
} }

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.bukkit.block.behavior; 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.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
@@ -11,51 +10,31 @@ import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.LazyReference;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFormEvent;
import org.jetbrains.annotations.Nullable;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class ConcretePowderBlockBehavior extends BukkitBlockBehavior { public class ConcretePowderBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Key targetBlock; // TODO 更宽泛的使用state似乎也不是很好的方案 private final LazyReference<@Nullable ImmutableBlockState> targetBlock;
private Object defaultBlockState;
private ImmutableBlockState defaultImmutableBlockState;
public ConcretePowderBlockBehavior(CustomBlock block, Key targetBlock) { public ConcretePowderBlockBehavior(CustomBlock block, String targetBlock) {
super(block); super(block);
this.targetBlock = targetBlock; this.targetBlock = LazyReference.lazyReference(() -> BlockStateParser.deserialize(targetBlock));
}
public ImmutableBlockState defaultImmutableBlockState() {
if (this.defaultImmutableBlockState == null) {
this.getDefaultBlockState();
}
return this.defaultImmutableBlockState;
} }
public Object getDefaultBlockState() { public Object getDefaultBlockState() {
if (this.defaultBlockState != null) { ImmutableBlockState state = this.targetBlock.get();
return this.defaultBlockState; return state != null ? state.customBlockState().literalObject() : MBlocks.STONE$defaultState;
}
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().blockById(this.targetBlock);
if (optionalCustomBlock.isPresent()) {
CustomBlock customBlock = optionalCustomBlock.get();
this.defaultBlockState = customBlock.defaultState().customBlockState().literalObject();
this.defaultImmutableBlockState = customBlock.defaultState();
} else {
CraftEngine.instance().logger().warn("Failed to create solid block " + this.targetBlock + " in ConcretePowderBlockBehavior");
this.defaultBlockState = MBlocks.STONE$defaultState;
this.defaultImmutableBlockState = EmptyBlock.STATE;
}
return this.defaultBlockState;
} }
@SuppressWarnings("UnstableApiUsage") @SuppressWarnings("UnstableApiUsage")
@@ -72,7 +51,7 @@ public class ConcretePowderBlockBehavior extends BukkitBlockBehavior {
craftBlockState.setBlockData(BlockStateUtils.fromBlockData(getDefaultBlockState())); craftBlockState.setBlockData(BlockStateUtils.fromBlockData(getDefaultBlockState()));
BlockFormEvent event = new BlockFormEvent(craftBlockState.getBlock(), craftBlockState); BlockFormEvent event = new BlockFormEvent(craftBlockState.getBlock(), craftBlockState);
if (!EventUtils.fireAndCheckCancel(event)) { if (!EventUtils.fireAndCheckCancel(event)) {
return defaultImmutableBlockState(); return this.targetBlock.get();
} else { } else {
return super.updateStateForPlacement(context, state); return super.updateStateForPlacement(context, state);
} }
@@ -148,7 +127,7 @@ public class ConcretePowderBlockBehavior extends BukkitBlockBehavior {
@Override @Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) { public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
String solidBlock = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("solid-block"), "warning.config.block.behavior.concrete.missing_solid"); String solidBlock = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("solid-block"), "warning.config.block.behavior.concrete.missing_solid");
return new ConcretePowderBlockBehavior(block, Key.of(solidBlock)); return new ConcretePowderBlockBehavior(block, solidBlock);
} }
} }
} }

View File

@@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.IntegerProperty;
import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.entity.player.InteractionResult; 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.Item;
import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
@@ -121,14 +122,15 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
} }
@Override @Override
public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { public void performBoneMeal(Object thisBlock, Object[] args) {
this.performBoneMeal(args[0], args[2], args[3]); this.performBoneMeal(args[0], args[2], args[3]);
} }
@Override @Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Item<?> item = context.getItem(); Item<?> item = context.getItem();
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) Player player = context.getPlayer();
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || player == null || player.isAdventureMode())
return InteractionResult.PASS; return InteractionResult.PASS;
if (isMaxAge(state)) if (isMaxAge(state))
return InteractionResult.PASS; return InteractionResult.PASS;
@@ -144,7 +146,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
sendSwing = true; sendSwing = true;
} }
if (sendSwing) { if (sendSwing) {
context.getPlayer().swingHand(context.getHand()); player.swingHand(context.getHand());
} }
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }

View File

@@ -145,6 +145,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior implements IsPat
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void playerToggle(UseOnContext context, ImmutableBlockState state) { private void playerToggle(UseOnContext context, ImmutableBlockState state) {
Player player = context.getPlayer(); Player player = context.getPlayer();
if (player == null) return;
this.toggle(state, context.getLevel(), context.getClickedPos(), player); this.toggle(state, context.getLevel(), context.getClickedPos(), player);
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().literalObject()), context.getHitResult(), (Item<ItemStack>) context.getItem())) { if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().literalObject()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
player.swingHand(context.getHand()); player.swingHand(context.getHand());

View File

@@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.entity.player.InteractionResult; 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.Item;
import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
@@ -83,7 +84,8 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
@Override @Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Item<?> item = context.getItem(); Item<?> item = context.getItem();
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) Player player = context.getPlayer();
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || player == null || player.isAdventureMode())
return InteractionResult.PASS; return InteractionResult.PASS;
BlockPos pos = context.getClickedPos(); BlockPos pos = context.getClickedPos();
BukkitExistingBlock upper = (BukkitExistingBlock) context.getLevel().getBlock(pos.x(), pos.y() + 1, pos.z()); BukkitExistingBlock upper = (BukkitExistingBlock) context.getLevel().getBlock(pos.x(), pos.y() + 1, pos.z());
@@ -102,7 +104,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
sendSwing = true; sendSwing = true;
} }
if (sendSwing) { if (sendSwing) {
context.getPlayer().swingHand(context.getHand()); player.swingHand(context.getHand());
} }
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }

View File

@@ -0,0 +1,93 @@
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.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.behavior.IsPathFindableBlockBehavior;
import net.momirealms.craftengine.core.block.properties.BooleanProperty;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.concurrent.Callable;
public class HangableBlockBehavior extends BukkitBlockBehavior implements IsPathFindableBlockBehavior {
public static final Factory FACTORY = new Factory();
private final BooleanProperty hanging;
public HangableBlockBehavior(CustomBlock customBlock, BooleanProperty hanging) {
super(customBlock);
this.hanging = hanging;
}
@Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
BooleanProperty hanging = (BooleanProperty) state.owner().value().getProperty("hanging");
if (hanging == null) return state;
@Nullable BooleanProperty waterlogged = (BooleanProperty) state.owner().value().getProperty("waterlogged");
Object world = context.getLevel().serverWorld();
Object blockPos = LocationUtils.toBlockPos(context.getClickedPos());
Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, blockPos));
for (Direction direction : context.getNearestLookingDirections()) {
if (direction.axis() != Direction.Axis.Y) continue;
ImmutableBlockState blockState = state.with(hanging, direction == Direction.UP);
if (!FastNMS.INSTANCE.method$BlockStateBase$canSurvive(blockState.customBlockState().literalObject(), world, blockPos)) continue;
return waterlogged != null ? blockState.with(waterlogged, fluidType == MFluids.WATER) : blockState;
}
return state;
}
@Override
public boolean canSurvive(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object state = args[0];
Object world = args[1];
Object blockPos = args[2];
ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null);
if (blockState == null) return false;
BooleanProperty hangingProperty = (BooleanProperty) blockState.owner().value().getProperty("hanging");
if (hangingProperty == null) return false;
Boolean hanging = blockState.get(hangingProperty);
Object relativePos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, hanging ? CoreReflections.instance$Direction$UP : CoreReflections.instance$Direction$DOWN);
return FastNMS.INSTANCE.method$Block$canSupportCenter(world, relativePos, hanging ? CoreReflections.instance$Direction$DOWN : CoreReflections.instance$Direction$UP);
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null);
if (state == null) return MBlocks.AIR$defaultState;
@Nullable BooleanProperty waterlogged = (BooleanProperty) state.owner().value().getProperty("waterlogged");
if (waterlogged != null && state.get(waterlogged)) {
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
}
BooleanProperty hanging = (BooleanProperty) state.owner().value().getProperty("hanging");
if (hanging == null) return MBlocks.AIR$defaultState;
if ((state.get(hanging) ? CoreReflections.instance$Direction$UP : CoreReflections.instance$Direction$DOWN) == args[updateShape$direction]
&& !FastNMS.INSTANCE.method$BlockStateBase$canSurvive(args[0], args[updateShape$level], args[updateShape$blockPos])) {
return MBlocks.AIR$defaultState;
}
return superMethod.call();
}
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
return false;
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
BooleanProperty hanging = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("hanging"), "warning.config.block.behavior.hangable.missing_hanging");
return new HangableBlockBehavior(block, hanging);
}
}
}

View File

@@ -165,7 +165,7 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) { public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<Boolean> persistent = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("persistent"), "warning.config.block.behavior.leaves.missing_persistent"); Property<Boolean> persistent = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("persistent"), "warning.config.block.behavior.leaves.missing_persistent");
Property<Integer> distance = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("distance"), "warning.config.block.behavior.leaves.missing_distance"); Property<Integer> distance = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("distance"), "warning.config.block.behavior.leaves.missing_distance");
int actual = distance.possibleValues().get(distance.possibleValues().size() - 1); int actual = distance.possibleValues().getLast();
return new LeavesBlockBehavior(block, actual, distance, persistent); return new LeavesBlockBehavior(block, actual, distance, persistent);
} }
} }

View File

@@ -16,6 +16,7 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.IntegerProperty;
import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.entity.player.InteractionResult; 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.Item;
import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
@@ -148,7 +149,8 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
@Override @Override
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Item<?> item = context.getItem(); Item<?> item = context.getItem();
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) Player player = context.getPlayer();
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || player == null || player.isAdventureMode())
return InteractionResult.PASS; return InteractionResult.PASS;
boolean sendSwing = false; boolean sendSwing = false;
Object visualState = state.vanillaBlockState().literalObject(); Object visualState = state.vanillaBlockState().literalObject();
@@ -162,7 +164,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
sendSwing = true; sendSwing = true;
} }
if (sendSwing) { if (sendSwing) {
context.getPlayer().swingHand(context.getHand()); player.swingHand(context.getHand());
} }
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }

View File

@@ -46,7 +46,7 @@ public class StackableBlockBehavior extends BukkitBlockBehavior {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Player player = context.getPlayer(); Player player = context.getPlayer();
if (player.isSecondaryUseActive()) { if (player == null || player.isSecondaryUseActive()) {
return InteractionResult.PASS; return InteractionResult.PASS;
} }
Item<ItemStack> item = (Item<ItemStack>) context.getItem(); Item<ItemStack> item = (Item<ItemStack>) context.getItem();

View File

@@ -118,6 +118,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior implements IsPath
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void playerToggle(UseOnContext context, ImmutableBlockState state) { private void playerToggle(UseOnContext context, ImmutableBlockState state) {
Player player = context.getPlayer(); Player player = context.getPlayer();
if (player == null) return;
this.toggle(state, context.getLevel(), context.getClickedPos(), player); this.toggle(state, context.getLevel(), context.getClickedPos(), player);
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().literalObject()), context.getHitResult(), (Item<ItemStack>) context.getItem())) { if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().literalObject()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
player.swingHand(context.getHand()); player.swingHand(context.getHand());

View File

@@ -7,21 +7,16 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.Tristate;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Map; import java.util.Map;
public class WallBlockItemBehavior extends BlockItemBehavior { public class WallBlockItemBehavior extends BlockItemBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Tristate hanging;
public WallBlockItemBehavior(Key wallBlockId, Tristate hanging) { public WallBlockItemBehavior(Key wallBlockId) {
super(wallBlockId); super(wallBlockId);
this.hanging = hanging;
} }
@Override @Override
@@ -34,21 +29,8 @@ public class WallBlockItemBehavior extends BlockItemBehavior {
if (context.getClickedFace().stepY() != 0) { if (context.getClickedFace().stepY() != 0) {
return InteractionResult.PASS; return InteractionResult.PASS;
} }
if (this.hanging == Tristate.UNDEFINED) {
return super.place(context); return super.place(context);
} }
for (Direction direction : context.getNearestLookingDirections()) {
if (direction.axis() != Direction.Axis.Y) continue;
if (this.hanging == Tristate.FALSE) {
if (direction == Direction.DOWN) return super.place(context);
if (direction == Direction.UP) break;
} else if (this.hanging == Tristate.TRUE) {
if (direction == Direction.UP) return super.place(context);
if (direction == Direction.DOWN) break;
}
}
return InteractionResult.PASS;
}
public static class Factory implements ItemBehaviorFactory { public static class Factory implements ItemBehaviorFactory {
@Override @Override
@@ -57,12 +39,11 @@ public class WallBlockItemBehavior extends BlockItemBehavior {
if (id == null) { if (id == null) {
throw new LocalizedResourceConfigException("warning.config.item.behavior.wall_block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for wall_block_item behavior")); throw new LocalizedResourceConfigException("warning.config.item.behavior.wall_block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for wall_block_item behavior"));
} }
Tristate hanging = arguments.containsKey("hanging") ? Tristate.of(ResourceConfigUtils.getAsBoolean(arguments.get("hanging"), "hanging")) : Tristate.UNDEFINED;
if (id instanceof Map<?, ?> map) { if (id instanceof Map<?, ?> map) {
addPendingSection(pack, path, node, key, map); addPendingSection(pack, path, node, key, map);
return new WallBlockItemBehavior(key, hanging); return new WallBlockItemBehavior(key);
} else { } else {
return new WallBlockItemBehavior(Key.of(id.toString()), hanging); return new WallBlockItemBehavior(Key.of(id.toString()));
} }
} }
} }

View File

@@ -365,6 +365,7 @@ warning.config.block.behavior.attached_stem.missing_stem: "<yellow>Issue found i
warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'sounds.projectile-hit' argument for 'chime_block' behavior.</yellow>" warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'sounds.projectile-hit' argument for 'chime_block' behavior.</yellow>"
warning.config.block.behavior.surface_spreading.missing_base_block: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'base-block' argument for 'surface_spreading_block' behavior.</yellow>" warning.config.block.behavior.surface_spreading.missing_base_block: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'base-block' argument for 'surface_spreading_block' behavior.</yellow>"
warning.config.block.behavior.snowy.missing_snowy: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'snowy' property for 'snowy_block' behavior.</yellow>" warning.config.block.behavior.snowy.missing_snowy: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'snowy' property for 'snowy_block' behavior.</yellow>"
warning.config.block.behavior.hangable.missing_hanging: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'hanging' property for 'hangable_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.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.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>" 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

@@ -365,6 +365,7 @@ warning.config.block.behavior.attached_stem.missing_stem: "<yellow>在文件 <ar
warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'chime_block' 行为缺少必需的 'sounds.projectile-hit' 选项</yellow>" warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'chime_block' 行为缺少必需的 'sounds.projectile-hit' 选项</yellow>"
warning.config.block.behavior.surface_spreading.missing_base_block: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'surface_spreading_block' 行为缺少必需的 'base-block' 选项</yellow>" warning.config.block.behavior.surface_spreading.missing_base_block: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'surface_spreading_block' 行为缺少必需的 'base-block' 选项</yellow>"
warning.config.block.behavior.snowy.missing_snowy: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'snowy_block' 行为缺少必需的 'snowy' 属性</yellow>" warning.config.block.behavior.snowy.missing_snowy: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'snowy_block' 行为缺少必需的 'snowy' 属性</yellow>"
warning.config.block.behavior.hangable.missing_hanging: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'hangable_block' 行为缺少必需的 'hanging' 属性</yellow>"
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</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.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>" warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>"

View File

@@ -73,7 +73,7 @@ public abstract class BlockBehavior {
superMethod.call(); superMethod.call();
} }
// 1.20+ BlockState state, LevelReader world, BlockPos pos // BlockState state, LevelReader world, BlockPos pos
public boolean canSurvive(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception { public boolean canSurvive(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return (boolean) superMethod.call(); return (boolean) superMethod.call();
} }