mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-30 04:19:27 +00:00
feat(block): 添加放置方块行为的黑白名单功能
This commit is contained in:
@@ -9,17 +9,42 @@ import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public abstract class FacingTriggerableBlockBehavior extends BukkitBlockBehavior {
|
||||
protected static final List<Key> DEFAULT_BLACKLIST_BLOCKS = List.of(
|
||||
Key.of("minecraft:bedrock"),
|
||||
Key.of("minecraft:end_portal_frame"),
|
||||
Key.of("minecraft:end_portal"),
|
||||
Key.of("minecraft:nether_portal"),
|
||||
Key.of("minecraft:barrier"),
|
||||
Key.of("minecraft:command_block"),
|
||||
Key.of("minecraft:chain_command_block"),
|
||||
Key.of("minecraft:repeating_command_block"),
|
||||
Key.of("minecraft:structure_block"),
|
||||
Key.of("minecraft:end_gateway"),
|
||||
Key.of("minecraft:jigsaw"),
|
||||
Key.of("minecraft:structure_void"),
|
||||
Key.of("minecraft:test_instance_block"),
|
||||
Key.of("minecraft:moving_piston"),
|
||||
Key.of("minecraft:test_block"),
|
||||
Key.of("minecraft:light")
|
||||
);
|
||||
protected final Property<Direction> facingProperty;
|
||||
protected final Property<Boolean> triggeredProperty;
|
||||
protected final List<Key> blocks;
|
||||
protected final boolean whitelistMode;
|
||||
|
||||
public FacingTriggerableBlockBehavior(CustomBlock customBlock, Property<Direction> facing, Property<Boolean> triggered) {
|
||||
public FacingTriggerableBlockBehavior(CustomBlock customBlock, Property<Direction> facing, Property<Boolean> triggered, List<Key> blocks, boolean whitelistMode) {
|
||||
super(customBlock);
|
||||
this.facingProperty = facing;
|
||||
this.triggeredProperty = triggered;
|
||||
this.blocks = blocks;
|
||||
this.whitelistMode = whitelistMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,6 +75,17 @@ public abstract class FacingTriggerableBlockBehavior extends BukkitBlockBehavior
|
||||
return state.owner().value().defaultState().with(this.facingProperty, direction);
|
||||
}
|
||||
|
||||
protected boolean blockCheck(Object blockState) {
|
||||
if (blockState == null || FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) {
|
||||
return false;
|
||||
}
|
||||
Key blockId = Optional.ofNullable(BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)))
|
||||
.filter(state -> !state.isEmpty())
|
||||
.map(state -> state.owner().value().id())
|
||||
.orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(blockState));
|
||||
return this.blocks.contains(blockId) == this.whitelistMode;
|
||||
}
|
||||
|
||||
protected abstract Object getTickPriority();
|
||||
|
||||
protected abstract void tick(Object state, Object level, Object pos);
|
||||
|
||||
@@ -17,36 +17,13 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class PickaxeBlockBehavior extends FacingTriggerableBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private static final List<Key> DEFAULT_BLACK_BLOCKS = List.of(
|
||||
Key.of("minecraft:bedrock"),
|
||||
Key.of("minecraft:end_portal_frame"),
|
||||
Key.of("minecraft:end_portal"),
|
||||
Key.of("minecraft:nether_portal"),
|
||||
Key.of("minecraft:barrier"),
|
||||
Key.of("minecraft:command_block"),
|
||||
Key.of("minecraft:chain_command_block"),
|
||||
Key.of("minecraft:repeating_command_block"),
|
||||
Key.of("minecraft:structure_block"),
|
||||
Key.of("minecraft:end_gateway"),
|
||||
Key.of("minecraft:jigsaw"),
|
||||
Key.of("minecraft:structure_void"),
|
||||
Key.of("minecraft:test_instance_block"),
|
||||
Key.of("minecraft:moving_piston"),
|
||||
Key.of("minecraft:test_block"),
|
||||
Key.of("minecraft:light")
|
||||
);
|
||||
private final List<Key> blocks;
|
||||
private final boolean whitelistMode;
|
||||
|
||||
public PickaxeBlockBehavior(CustomBlock customBlock, Property<Direction> facing, Property<Boolean> triggered, List<Key> blocks, boolean whitelistMode) {
|
||||
super(customBlock, facing, triggered);
|
||||
this.blocks = blocks;
|
||||
this.whitelistMode = whitelistMode;
|
||||
super(customBlock, facing, triggered, blocks, whitelistMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,22 +44,11 @@ public class PickaxeBlockBehavior extends FacingTriggerableBlockBehavior {
|
||||
ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (blockState == null || blockState.isEmpty()) return;
|
||||
Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, DirectionUtils.toNMSDirection(blockState.get(this.facingProperty)));
|
||||
if (breakCheck(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos))) {
|
||||
if (blockCheck(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos))) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$destroyBlock(level, blockPos, true, null, 512);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean breakCheck(Object blockState) {
|
||||
if (blockState == null || FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) {
|
||||
return false;
|
||||
}
|
||||
Key blockId = Optional.ofNullable(BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)))
|
||||
.filter(state -> !state.isEmpty())
|
||||
.map(state -> state.owner().value().id())
|
||||
.orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(blockState));
|
||||
return this.blocks.contains(blockId) == this.whitelistMode;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
@@ -93,7 +59,7 @@ public class PickaxeBlockBehavior extends FacingTriggerableBlockBehavior {
|
||||
boolean whitelistMode = (boolean) arguments.getOrDefault("whitelist", false);
|
||||
List<Key> blocks = MiscUtils.getAsStringList(arguments.get("blocks")).stream().map(Key::of).toList();
|
||||
if (blocks.isEmpty() && !whitelistMode) {
|
||||
blocks = DEFAULT_BLACK_BLOCKS;
|
||||
blocks = FacingTriggerableBlockBehavior.DEFAULT_BLACKLIST_BLOCKS;
|
||||
}
|
||||
return new PickaxeBlockBehavior(block, facing, triggered, blocks, whitelistMode);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.Location;
|
||||
@@ -38,8 +40,8 @@ import java.util.function.Function;
|
||||
public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
|
||||
public PlaceBlockBehavior(CustomBlock customBlock, Property<Direction> facing, Property<Boolean> triggered) {
|
||||
super(customBlock, facing, triggered);
|
||||
public PlaceBlockBehavior(CustomBlock customBlock, Property<Direction> facing, Property<Boolean> triggered, List<Key> blocks, boolean whitelistMode) {
|
||||
super(customBlock, facing, triggered, blocks, whitelistMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,17 +71,23 @@ public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior {
|
||||
return false;
|
||||
} else {
|
||||
Object itemStack1 = FastNMS.INSTANCE.method$ItemStack$getItem(itemStack);
|
||||
boolean flag = CoreReflections.clazz$BlockItem.isInstance(itemStack1)
|
||||
&& FastNMS.INSTANCE.method$InteractionResult$consumesAction(FastNMS.INSTANCE.method$BlockItem$place(
|
||||
itemStack1, FastNMS.INSTANCE.constructor$PlaceBlockBlockPlaceContext(
|
||||
level, CoreReflections.instance$InteractionHand$MAIN_HAND, itemStack,
|
||||
FastNMS.INSTANCE.constructor$BlockHitResult(
|
||||
FastNMS.INSTANCE.method$BlockPos$getCenter(LocationUtils.toBlockPos(blockPos1)),
|
||||
DirectionUtils.toNMSDirection(opposite),
|
||||
LocationUtils.toBlockPos(blockPos1),
|
||||
false
|
||||
)
|
||||
)));
|
||||
boolean flag = false;
|
||||
if (CoreReflections.clazz$BlockItem.isInstance(itemStack1)) {
|
||||
Object block = FastNMS.INSTANCE.method$BlockItem$getBlock(itemStack1);
|
||||
if (blockCheck(FastNMS.INSTANCE.method$Block$defaultState(block))) {
|
||||
Object blockHitResult = FastNMS.INSTANCE.constructor$BlockHitResult(
|
||||
FastNMS.INSTANCE.method$BlockPos$getCenter(LocationUtils.toBlockPos(blockPos1)),
|
||||
DirectionUtils.toNMSDirection(opposite),
|
||||
LocationUtils.toBlockPos(blockPos1),
|
||||
false
|
||||
);
|
||||
Object placeBlockBlockPlaceContext = FastNMS.INSTANCE.constructor$PlaceBlockBlockPlaceContext(
|
||||
level, CoreReflections.instance$InteractionHand$MAIN_HAND, itemStack, blockHitResult
|
||||
);
|
||||
Object interactionResult = FastNMS.INSTANCE.method$BlockItem$place(itemStack1, placeBlockBlockPlaceContext);
|
||||
flag = FastNMS.INSTANCE.method$InteractionResult$consumesAction(interactionResult);
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
Item<ItemStack> item = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack));
|
||||
@@ -93,12 +101,19 @@ public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior {
|
||||
CraftEngine.instance().logger().warn("Failed to place unknown block " + blockItemBehavior.block());
|
||||
continue;
|
||||
}
|
||||
ImmutableBlockState placeBlockState = optionalBlock.get().defaultState();
|
||||
if (placeBlockState.contains(this.facingProperty)) {
|
||||
placeBlockState = placeBlockState.with(this.facingProperty, opposite);
|
||||
}
|
||||
if (blockCheck(placeBlockState.customBlockState().handle())) {
|
||||
continue;
|
||||
}
|
||||
Location placeLocation = new Location(FastNMS.INSTANCE.method$Level$getCraftWorld(level), blockPos1.x(), blockPos1.y(), blockPos1.z());
|
||||
if (placeLocation.getBlock().getType() != Material.AIR) {
|
||||
break;
|
||||
}
|
||||
// TODO: 修复放置多方块自定义方块问题
|
||||
if (CraftEngineBlocks.place(placeLocation, optionalBlock.get().defaultState(), UpdateOption.UPDATE_ALL_IMMEDIATE, true)) {
|
||||
if (CraftEngineBlocks.place(placeLocation, placeBlockState, UpdateOption.UPDATE_ALL_IMMEDIATE, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -211,7 +226,12 @@ public class PlaceBlockBehavior extends FacingTriggerableBlockBehavior {
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<Direction> facing = (Property<Direction>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.place_block.missing_facing");
|
||||
Property<Boolean> triggered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("triggered"), "warning.config.block.behavior.place_block.missing_triggered");
|
||||
return new PlaceBlockBehavior(block, facing, triggered);
|
||||
boolean whitelistMode = (boolean) arguments.getOrDefault("whitelist", false);
|
||||
List<Key> blocks = MiscUtils.getAsStringList(arguments.get("blocks")).stream().map(Key::of).toList();
|
||||
if (blocks.isEmpty() && !whitelistMode) {
|
||||
blocks = FacingTriggerableBlockBehavior.DEFAULT_BLACKLIST_BLOCKS;
|
||||
}
|
||||
return new PlaceBlockBehavior(block, facing, triggered, blocks, whitelistMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +92,7 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
}
|
||||
|
||||
public void setJavaComponent(Object type, Object value) {
|
||||
setSparrowNBTComponent(type, MRegistryOps.JAVA.convertTo(MRegistryOps.SPARROW_NBT, value));
|
||||
// setComponentInternal(type, MRegistryOps.JAVA, value); // 这里可能出现潜在的Integer和Boolean不区分问题
|
||||
setComponentInternal(type, MRegistryOps.JAVA, value);
|
||||
}
|
||||
|
||||
public void setJsonComponent(Object type, JsonElement value) {
|
||||
|
||||
@@ -162,6 +162,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
|
||||
registerNMSPacketConsumer(PacketConsumers.ROTATE_HEAD, NetworkReflections.clazz$ClientboundRotateHeadPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_MOTION, NetworkReflections.clazz$ClientboundSetEntityMotionPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.CLIENT_INFO, NetworkReflections.clazz$ServerboundClientInformationPacket);
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
|
||||
|
||||
@@ -2414,4 +2414,23 @@ public class PacketConsumers {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CLIENT_INFO = (user, event, packet) -> {
|
||||
try {
|
||||
Map<String, Object> information = FastNMS.INSTANCE.method$ServerboundClientInformationPacket$information(packet);
|
||||
user.setClientInformation(new ClientInformation(
|
||||
(String) information.getOrDefault("language", "en_us"),
|
||||
(int) information.getOrDefault("viewDistance", 2),
|
||||
information.getOrDefault("chatVisibility", null),
|
||||
(boolean) information.getOrDefault("chatColors", true),
|
||||
(int) information.getOrDefault("modelCustomisation", 0),
|
||||
information.getOrDefault("mainHand", null),
|
||||
(boolean) information.getOrDefault("textFilteringEnabled", false),
|
||||
(boolean) information.getOrDefault("allowsListing", false),
|
||||
information.getOrDefault("particleStatus", null)
|
||||
));
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1089,20 +1089,12 @@ public final class NetworkReflections {
|
||||
ReflectionUtils.getDeclaredConstructor(clazz$ClientboundMoveEntityPacket$Pos, int.class, short.class, short.class, short.class, boolean.class)
|
||||
);
|
||||
|
||||
// 1.20.2+
|
||||
public static final Class<?> clazz$ServerboundClientInformationPacket =
|
||||
ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundClientInformationPacket"));
|
||||
|
||||
// 1.20.2+
|
||||
public static final Constructor<?> constructor$ServerboundClientInformationPacket = Optional.ofNullable(clazz$ServerboundClientInformationPacket)
|
||||
.map(it -> ReflectionUtils.getConstructor(it, 1))
|
||||
.orElse(null);
|
||||
|
||||
// 1.20.2+
|
||||
public static final Field field$ServerboundClientInformationPacket$information = Optional.ofNullable(clazz$ServerboundClientInformationPacket)
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, 0))
|
||||
.orElse(null);
|
||||
|
||||
public static final Class<?> clazz$ServerboundClientInformationPacket = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
List.of("network.protocol.game.PacketPlayInSettings", "network.protocol.common.ServerboundClientInformationPacket"),
|
||||
List.of("network.protocol.game.ServerboundClientInformationPacket", "network.protocol.common.ServerboundClientInformationPacket")
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$ClientboundSetTitleTextPacket = requireNonNull(
|
||||
ReflectionUtils.getClazz(
|
||||
|
||||
@@ -31,6 +31,7 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState;
|
||||
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
|
||||
import net.momirealms.craftengine.core.plugin.network.ProtocolVersion;
|
||||
import net.momirealms.craftengine.core.sound.SoundSource;
|
||||
import net.momirealms.craftengine.core.util.ClientInformation;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
@@ -75,6 +76,7 @@ public class BukkitServerPlayer extends Player {
|
||||
// client side dimension info
|
||||
private int sectionCount;
|
||||
private Key clientSideDimension;
|
||||
private ClientInformation clientInformation;
|
||||
// check main hand/offhand interaction
|
||||
private int lastSuccessfulInteraction;
|
||||
// re-sync attribute timely to prevent some bugs
|
||||
@@ -884,6 +886,16 @@ public class BukkitServerPlayer extends Player {
|
||||
this.sentResourcePack = sentResourcePack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInformation(ClientInformation clientInfo) {
|
||||
this.clientInformation = clientInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientInformation getClientInformation() {
|
||||
return this.clientInformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView() {
|
||||
this.entityTypeView.clear();
|
||||
|
||||
Reference in New Issue
Block a user