diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index c21500bb8..b7cb6fd32 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -4,8 +4,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior; -import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior; +import net.momirealms.craftengine.bukkit.item.behavior.*; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener; import net.momirealms.craftengine.bukkit.item.listener.DebugStickListener; @@ -41,6 +40,9 @@ public class BukkitItemManager extends AbstractItemManager { static { registerVanillaItemExtraBehavior(FlintAndSteelItemBehavior.INSTANCE, ItemKeys.FLINT_AND_STEEL); registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.AXES); + registerVanillaItemExtraBehavior(CompassItemBehavior.INSTANCE, ItemKeys.COMPASS); + registerVanillaItemExtraBehavior(EnderEyeItemBehavior.INSTANCE, ItemKeys.ENDER_EYE); + registerVanillaItemExtraBehavior(EndCrystalItemBehavior.INSTANCE, ItemKeys.END_CRYSTAL); } private static BukkitItemManager instance; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index af61198c2..e928f9233 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -108,10 +108,7 @@ public class AxeItemBehavior extends ItemBehavior { if (!InteractUtils.isInteractable( bukkitPlayer, BlockStateUtils.fromBlockData(customState.vanillaBlockState().literalObject()), context.getHitResult(), item - ) || (player.isSecondaryUseActive() && !InteractUtils.isIgnoreSneaking( - bukkitPlayer, BlockStateUtils.fromBlockData(customState.vanillaBlockState().literalObject()), - context.getHitResult(), item - ))) { + ) || player.isSecondaryUseActive()) { player.swingHand(context.getHand()); } // shrink item amount diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java index 79292cfda..c045bfa96 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java @@ -12,6 +12,9 @@ public class BukkitItemBehaviors extends ItemBehaviors { public static final Key COMPOSTABLE_ITEM = Key.from("craftengine:compostable_item"); public static final Key AXE_ITEM = Key.from("craftengine:axe_item"); public static final Key DOUBLE_HIGH_BLOCK_ITEM = Key.from("craftengine:double_high_block_item"); + public static final Key COMPASS_ITEM = Key.from("craftengine:compass_item"); + public static final Key ENDER_EYE_ITEM = Key.from("craftengine:ender_eye_item"); + public static final Key END_CRYSTAL_ITEM = Key.from("craftengine:end_crystal_item"); public static void init() { register(EMPTY, EmptyItemBehavior.FACTORY); @@ -22,5 +25,8 @@ public class BukkitItemBehaviors extends ItemBehaviors { register(COMPOSTABLE_ITEM, CompostableItemBehavior.FACTORY); register(AXE_ITEM, AxeItemBehavior.FACTORY); register(DOUBLE_HIGH_BLOCK_ITEM, DoubleHighBlockItemBehavior.FACTORY); + register(COMPASS_ITEM, CompassItemBehavior.FACTORY); + register(ENDER_EYE_ITEM, EnderEyeItemBehavior.FACTORY); + register(END_CRYSTAL_ITEM, EndCrystalItemBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompassItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompassItemBehavior.java new file mode 100644 index 000000000..1d23cab4e --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompassItemBehavior.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.bukkit.item.behavior; + +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.block.data.BlockData; + +import java.nio.file.Path; +import java.util.Map; + +public class CompassItemBehavior extends ItemBehavior { + public static final CompassItemBehavior INSTANCE = new CompassItemBehavior(); + public static final CompassItemBehavior.Factory FACTORY = new CompassItemBehavior.Factory(); + + @Override + public InteractionResult useOnBlock(UseOnContext context) { + BukkitExistingBlock block = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos()); + BlockData blockData = block.block().getBlockData(); + Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData)); + + if (blockOwner != MBlocks.LODESTONE) { + return InteractionResult.PASS; + } else { + return InteractionResult.SUCCESS; + } + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + return INSTANCE; + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/EndCrystalItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/EndCrystalItemBehavior.java new file mode 100644 index 000000000..7b959ccf3 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/EndCrystalItemBehavior.java @@ -0,0 +1,76 @@ +package net.momirealms.craftengine.bukkit.item.behavior; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; +import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.collision.AABB; +import org.bukkit.block.data.BlockData; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +public class EndCrystalItemBehavior extends ItemBehavior { + public static final EndCrystalItemBehavior INSTANCE = new EndCrystalItemBehavior(); + public static final EndCrystalItemBehavior.Factory FACTORY = new EndCrystalItemBehavior.Factory(); + + @Override + public InteractionResult useOnBlock(UseOnContext context) { + World world = context.getLevel(); + BlockPos blockPos = context.getClickedPos(); + BukkitExistingBlock block = (BukkitExistingBlock) world.getBlockAt(blockPos); + BlockData blockData = block.block().getBlockData(); + Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData)); + + if (blockOwner != MBlocks.OBSIDIAN && blockOwner != MBlocks.BEDROCK) { + return InteractionResult.PASS; + } else { + BlockPos abovePos = blockPos.above(); + BukkitExistingBlock aboveBlock = (BukkitExistingBlock) world.getBlockAt(abovePos); + BlockData aboveBlockData = aboveBlock.block().getBlockData(); + Object aboveBlockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(aboveBlockData)); + + if (aboveBlockOwner != MBlocks.AIR) { + return InteractionResult.PASS; + } else { + + double x = abovePos.x(); + double y = abovePos.y(); + double z = abovePos.z(); + AABB aabb = new AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0); + List entities = world.getEntities(null, aabb); + if (!entities.isEmpty()) { + return InteractionResult.PASS; + } + + List aabbs = List.of(aabb); + List nmsAABB = aabbs.stream() + .map(AABB -> FastNMS.INSTANCE.constructor$AABB( + AABB.minX, AABB.minY, AABB.minZ, + AABB.maxX, AABB.maxY, AABB.maxZ + )).toList(); + if (!FastNMS.INSTANCE.checkEntityCollision(context.getLevel().serverWorld(), nmsAABB, x, y, z)) { + return InteractionResult.PASS; + } + return InteractionResult.SUCCESS; + } + } + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + return INSTANCE; + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/EnderEyeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/EnderEyeItemBehavior.java new file mode 100644 index 000000000..9fa969a98 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/EnderEyeItemBehavior.java @@ -0,0 +1,41 @@ +package net.momirealms.craftengine.bukkit.item.behavior; + +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.EndPortalFrame; + +import java.nio.file.Path; +import java.util.Map; + +public class EnderEyeItemBehavior extends ItemBehavior { + public static final EnderEyeItemBehavior INSTANCE = new EnderEyeItemBehavior(); + public static final EnderEyeItemBehavior.Factory FACTORY = new EnderEyeItemBehavior.Factory(); + + @Override + public InteractionResult useOnBlock(UseOnContext context) { + BukkitExistingBlock block = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos()); + BlockData blockData = block.block().getBlockData(); + Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData)); + + if (blockOwner != MBlocks.END_PORTAL_FRAME || (blockData instanceof EndPortalFrame endPortalFrame && endPortalFrame.hasEye())) { + return InteractionResult.PASS; + } else { + return InteractionResult.SUCCESS; + } + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + return INSTANCE; + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 653679a9d..ce1500a38 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -257,7 +257,7 @@ public class ItemEventListener implements Listener { // so we should check and resend sounds on BlockPlaceEvent BlockData craftBlockData = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().literalObject()); if (InteractUtils.isInteractable(player, craftBlockData, hitResult, itemInHand)) { - if (!serverPlayer.isSecondaryUseActive() || InteractUtils.isIgnoreSneaking(player, craftBlockData, hitResult, itemInHand)) { + if (!serverPlayer.isSecondaryUseActive()) { serverPlayer.setResendSound(); } } else { @@ -276,7 +276,7 @@ public class ItemEventListener implements Listener { return; } else { // todo 实际上这里的处理并不正确,因为判断玩家是否能够放置那个方块需要更加细节的判断。比如玩家无法对着树叶放置火把,但是交互事件依然触发,此情况下不可丢弃自定义行为。 - if ((serverPlayer.isSecondaryUseActive() && InteractUtils.isIgnoreSneaking(player, blockData, hitResult, itemInHand)) || !InteractUtils.isInteractable(player, blockData, hitResult, itemInHand)) { + if (serverPlayer.isSecondaryUseActive() || !InteractUtils.isInteractable(player, blockData, hitResult, itemInHand)) { event.setCancelled(true); } } @@ -290,10 +290,9 @@ public class ItemEventListener implements Listener { if (optionalItemBehaviors.isPresent()) { // 检测是否可交互应当只判断原版方块,因为自定义方块早就判断过了,如果可交互不可能到这一步 boolean interactable = immutableBlockState == null && InteractUtils.isInteractable(player, blockData, hitResult, itemInHand); - boolean isIgnoreSneaking = InteractUtils.isIgnoreSneaking(player, blockData, hitResult, itemInHand); // 如果方块可交互但是玩家没shift,那么原版的方块交互优先,取消自定义物品的behavior // todo 如果我的物品行为允许某些交互呢?是否值得进一步处理? - if ((!serverPlayer.isSecondaryUseActive() || isIgnoreSneaking) && interactable) { + if (!serverPlayer.isSecondaryUseActive() && interactable) { return; } UseOnContext useOnContext = new UseOnContext(serverPlayer, hand, itemInHand, hitResult); @@ -316,7 +315,7 @@ public class ItemEventListener implements Listener { // 执行物品右键事件 if (hasCustomItem) { // 要求服务端侧这个方块不可交互,或玩家处于潜行状态 - if ((serverPlayer.isSecondaryUseActive() && !InteractUtils.isIgnoreSneaking(player, blockData, hitResult, itemInHand)) || !InteractUtils.isInteractable(player, blockData, hitResult, itemInHand)) { + if (serverPlayer.isSecondaryUseActive() || !InteractUtils.isInteractable(player, blockData, hitResult, itemInHand)) { Cancellable dummy = Cancellable.dummy(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block)) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java index d8971adba..ccdb91f69 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java @@ -10,6 +10,8 @@ public final class MBlocks { public static final Object AIR$defaultState; public static final Object STONE; public static final Object STONE$defaultState; + public static final Object BEDROCK; + public static final Object OBSIDIAN; public static final Object FIRE; public static final Object SOUL_FIRE; public static final Object ICE; @@ -22,6 +24,8 @@ 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 LODESTONE; + public static final Object END_PORTAL_FRAME; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -35,6 +39,8 @@ public final class MBlocks { SOUL_FIRE = getById("soul_fire"); STONE = getById("stone"); STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE); + BEDROCK = getById("bedrock"); + OBSIDIAN = getById("obsidian"); ICE = getById("ice"); SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass"); SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS); @@ -45,5 +51,7 @@ public final class MBlocks { WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); TNT = getById("tnt"); TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT); + LODESTONE = getById("lodestone"); + END_PORTAL_FRAME = getById("end_portal_frame"); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index 85655a2f7..28191f095 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -3,7 +3,10 @@ package net.momirealms.craftengine.bukkit.util; import io.papermc.paper.entity.Shearable; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior; +import net.momirealms.craftengine.bukkit.item.behavior.EnderEyeItemBehavior; +import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior; import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; +import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.BlockKeys; import net.momirealms.craftengine.core.entity.EntityTypeKeys; @@ -16,16 +19,17 @@ import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.QuadFunction; -import net.momirealms.craftengine.core.util.TriFunction; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.ExistingBlock; -import org.bukkit.*; +import org.bukkit.DyeColor; +import org.bukkit.GameMode; +import org.bukkit.Registry; +import org.bukkit.World; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Levelled; import org.bukkit.block.data.Lightable; @@ -42,7 +46,6 @@ import java.util.Optional; public final class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); - private static final Map, BlockData, BlockHitResult, Boolean>> SNEAK_BYPASS = new HashMap<>(); private static final Map, BlockData, BlockHitResult, Boolean>> WILL_CONSUME = new HashMap<>(); private static final Map, Boolean>> ENTITY_INTERACTIONS = new HashMap<>(); @@ -61,63 +64,6 @@ public final class InteractUtils { Key id = item.vanillaId(); return ItemKeys.BUCKET.equals(id); }); - // 自然方块 - registerInteraction(BlockKeys.OBSIDIAN, (player, item, blockState, result) -> { - Key id = item.vanillaId(); - if (ItemKeys.END_CRYSTAL.equals(id)) { - World world = player.getWorld(); - BukkitWorld bukkitWorld = new BukkitWorld(world); - BlockPos blockPos = result.getBlockPos(); - BlockPos abovePos = blockPos.relative(Direction.UP); - ExistingBlock aboveBlock = bukkitWorld.getBlockAt(abovePos); - if (!aboveBlock.id().equals(BlockKeys.AIR)) { - return false; - } else { - return true; - // TODO 需要判定区域内无任何实体 -// double x = aboveBlock.x(); -// double y = aboveBlock.y(); -// double z = aboveBlock.z(); -// Object serverWorld = bukkitWorld.serverWorld(); -// AABB aabb = new AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0); -// Object nmsAABB = FastNMS.INSTANCE.constructor$AABB( -// aabb.minX, aabb.minY, aabb.minZ, -// aabb.maxX, aabb.maxY, aabb.maxZ -// ); -// boolean hasCollision = FastNMS.INSTANCE.checkEntityCollision(serverWorld, List.of(nmsAABB), x + 0.5, y + 1.0, z + 0.5); -// return !hasCollision; - } - } - return false; - }); - registerInteraction(BlockKeys.BEDROCK, (player, item, blockState, result) -> { - Key id = item.vanillaId(); - if (ItemKeys.END_CRYSTAL.equals(id)) { - World world = player.getWorld(); - BukkitWorld bukkitWorld = new BukkitWorld(world); - BlockPos blockPos = result.getBlockPos(); - BlockPos abovePos = blockPos.relative(Direction.UP); - ExistingBlock aboveBlock = bukkitWorld.getBlockAt(abovePos); - if (!aboveBlock.id().equals(BlockKeys.AIR)) { - return false; - } else { - return true; - // TODO 需要判定区域内无任何实体 -// double x = aboveBlock.x(); -// double y = aboveBlock.y(); -// double z = aboveBlock.z(); -// Object serverWorld = bukkitWorld.serverWorld(); -// AABB aabb = new AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0); -// Object nmsAABB = FastNMS.INSTANCE.constructor$AABB( -// aabb.minX, aabb.minY, aabb.minZ, -// aabb.maxX, aabb.maxY, aabb.maxZ -// ); -// boolean hasCollision = FastNMS.INSTANCE.checkEntityCollision(serverWorld, List.of(nmsAABB), x + 0.5, y + 1.0, z + 0.5); -// return !hasCollision; - } - } - return false; - }); // 功能方块 registerInteraction(BlockKeys.CRAFTING_TABLE, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.STONECUTTER, (player, item, blockState, result) -> true); @@ -190,10 +136,6 @@ public final class InteractUtils { return false; }); registerInteraction(BlockKeys.BEACON, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.LODESTONE, (player, item, blockState, result) -> { - Key id = item.vanillaId(); - return ItemKeys.COMPASS.equals(id); - }); registerInteraction(BlockKeys.BEE_NEST, (player, item, blockState, result) -> { if (blockState instanceof Beehive beehive && beehive.getHoneyLevel() == beehive.getMaximumHoneyLevel()) { Key id = item.vanillaId(); @@ -226,9 +168,11 @@ public final class InteractUtils { }); registerInteraction(BlockKeys.DRAGON_EGG, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.END_PORTAL_FRAME, (player, item, blockState, result) -> { - if (blockState instanceof EndPortalFrame endPortalFrame && !endPortalFrame.hasEye()) { - Key id = item.vanillaId(); - return ItemKeys.ENDER_EYE.equals(id); + Optional> behaviors = item.getItemBehavior(); + if (behaviors.isPresent()) { + for (ItemBehavior behavior : behaviors.get()) { + if (behavior instanceof EnderEyeItemBehavior) return true; + } } return false; }); @@ -242,7 +186,49 @@ public final class InteractUtils { return id.asString().endsWith("_spawn_egg"); }); // 红石方块 - registerInteraction(BlockKeys.REDSTONE_WIRE, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.REDSTONE_WIRE, (player, item, blockState, result) -> { + if (blockState instanceof RedstoneWire redstoneWire) { + boolean isCross = redstoneWire.getFace(BlockFace.EAST).equals(RedstoneWire.Connection.SIDE) + && redstoneWire.getFace(BlockFace.NORTH).equals(RedstoneWire.Connection.SIDE) + && redstoneWire.getFace(BlockFace.SOUTH).equals(RedstoneWire.Connection.SIDE) + && redstoneWire.getFace(BlockFace.WEST).equals(RedstoneWire.Connection.SIDE); + boolean isDot = redstoneWire.getFace(BlockFace.EAST).equals(RedstoneWire.Connection.NONE) + && redstoneWire.getFace(BlockFace.NORTH).equals(RedstoneWire.Connection.NONE) + && redstoneWire.getFace(BlockFace.SOUTH).equals(RedstoneWire.Connection.NONE) + && redstoneWire.getFace(BlockFace.WEST).equals(RedstoneWire.Connection.NONE); + if (isCross || isDot) { + BlockPos blockPos = result.getBlockPos(); + BukkitWorld bukkitWorld = new BukkitWorld(player.getWorld()); + World world = bukkitWorld.platformWorld(); + + Direction[] directions = {Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.NORTH}; + for (Direction direction : directions) { + BlockPos neighborPos = blockPos.relative(direction); + Block neighborBlock = world.getBlockAt(neighborPos.x(), neighborPos.y(), neighborPos.z()); + Key neighborBlockKey = new BukkitExistingBlock(neighborBlock).id(); + BlockData neighborBlockData = neighborBlock.getBlockData(); + boolean canConnection = ArrayUtils.contains(BlockKeys.REDSTONE_CONNECTION, neighborBlockKey) + || ArrayUtils.contains(BlockKeys.PRESSURE_PLATES, neighborBlockKey) + || ArrayUtils.contains(BlockKeys.BUTTONS, neighborBlockKey); + if (canConnection) { + return switch (neighborBlockData) { + case Repeater repeater -> { + Direction neighborDirection = DirectionUtils.toDirection(repeater.getFacing()); + yield !(neighborDirection == direction || neighborDirection == direction.opposite()); + } + case Observer observer -> { + Direction neighborDirection = DirectionUtils.toDirection(observer.getFacing()); + yield !(neighborDirection == direction); + } + default -> false; + }; + } + } + return true; + } + } + return false; + }); registerInteraction(BlockKeys.REPEATER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.COMPARATOR, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.LEVER, (player, item, blockState, result) -> true); @@ -252,8 +238,13 @@ public final class InteractUtils { registerInteraction(BlockKeys.CRAFTER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.TNT, (player, item, blockState, result) -> { - Key id = item.vanillaId(); - return ItemKeys.FLINT_AND_STEEL.equals(id); + Optional> behaviors = item.getItemBehavior(); + if (behaviors.isPresent()) { + for (ItemBehavior behavior : behaviors.get()) { + if (behavior instanceof FlintAndSteelItemBehavior) return true; + } + } + return false; }); registerInteraction(BlockKeys.REDSTONE_ORE, (player, item, blockState, result) -> { Optional> behaviors = item.getItemBehavior(); @@ -727,21 +718,6 @@ public final class InteractUtils { registerInteraction(BlockKeys.WARPED_WALL_HANGING_SIGN, (player, item, blockState, result) -> true); } - // 忽略潜行 - static { - registerSneakBypass(BlockKeys.LODESTONE, (player, item, blockState, result) -> { - Key id = item.vanillaId(); - return ItemKeys.COMPASS.equals(id); - }); - registerSneakBypass(BlockKeys.END_PORTAL_FRAME, (player, item, blockState, result) -> { - if (blockState instanceof EndPortalFrame endPortalFrame && !endPortalFrame.hasEye()) { - Key id = item.vanillaId(); - return ItemKeys.ENDER_EYE.equals(id); - } - return false; - }); - } - // 消耗 static { registerWillConsume(BlockKeys.CACTUS, (player, item, blockState, result) -> { @@ -794,7 +770,7 @@ public final class InteractUtils { registerEntityInteraction(EntityTypeKeys.SHEEP, (player, entity, item) -> { Key id = item.vanillaId(); - if (entity instanceof Sheep sheep && sheep.readyToBeSheared() && id.in(ItemKeys.DYES)) { + if (entity instanceof Sheep sheep && sheep.readyToBeSheared() && ArrayUtils.contains(ItemKeys.DYES, item)) { DyeColor sheepColor = sheep.getColor(); if (sheepColor != null) { String color = sheepColor.name().toLowerCase(); @@ -820,12 +796,17 @@ public final class InteractUtils { }); registerEntityInteraction(EntityTypeKeys.CREEPER, (player, entity, item) -> { - Key id = item.vanillaId(); - return canBeFeed(entity, item) || ItemKeys.FLINT_AND_STEEL.equals(id); + Optional> behaviors = item.getItemBehavior(); + if (behaviors.isPresent()) { + for (ItemBehavior behavior : behaviors.get()) { + if (behavior instanceof FlintAndSteelItemBehavior) return true; + } + } + return false; }); registerEntityInteraction(EntityTypeKeys.PIGLIN, (player, entity, item) -> { Key id = item.vanillaId(); - return canBeFeed(entity, item) || ItemKeys.GOLD_INGOT.equals(id); + return ItemKeys.GOLD_INGOT.equals(id); }); registerEntityInteraction(EntityTypeKeys.ARMADILLO, (player, entity, item) -> { Key id = item.vanillaId(); @@ -954,13 +935,6 @@ public final class InteractUtils { } } - private static void registerSneakBypass(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { - var previous = SNEAK_BYPASS.put(key, function); - if (previous != null) { - CraftEngine.instance().logger().warn("Duplicated interaction check: " + key); - } - } - private static void registerWillConsume(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { var previous = WILL_CONSUME.put(key, function); if (previous != null) { @@ -983,14 +957,6 @@ public final class InteractUtils { return false; } - public static boolean isIgnoreSneaking(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { - Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state); - if (SNEAK_BYPASS.containsKey(blockType)) { - return SNEAK_BYPASS.get(blockType).apply(player, item, state, hit); - } - return false; - } - public static boolean willConsume(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { if (item == null) return false; Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index bfb04f654..f7c2f3d9e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,27 +1,36 @@ package net.momirealms.craftengine.bukkit.world; +import com.google.common.collect.Lists; +import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.particle.ParticleData; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.SoundCategory; +import org.bukkit.entity.EnderDragonPart; import org.bukkit.entity.EntityType; import org.bukkit.entity.ExperienceOrb; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.BoundingBox; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.nio.file.Path; +import java.util.List; import java.util.UUID; +import java.util.function.Predicate; public class BukkitWorld implements World { private final WeakReference world; @@ -54,6 +63,49 @@ public class BukkitWorld implements World { return new BukkitExistingBlock(platformWorld().getBlockAt(x, y, z)); } + @Override + public List getEntities(@Nullable Entity entity, AABB aabb, Predicate predicate) { + List entities = Lists.newArrayList(); + Object nmsAABB = FastNMS.INSTANCE.constructor$AABB( + aabb.minX, aabb.minY, aabb.minZ, + aabb.maxX, aabb.maxY, aabb.maxZ + ); + BoundingBox bukkitAABB = new BoundingBox( + aabb.minX, aabb.minY, aabb.minZ, + aabb.maxX, aabb.maxY, aabb.maxZ + ); + Object level = serverWorld(); + int entityCount = FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass(level, nmsAABB, CoreReflections.clazz$Entity); + if (entityCount == 0) { + return entities; + } + for (org.bukkit.entity.Entity bukkitEntity : platformWorld().getNearbyEntities(bukkitAABB)) { + if (bukkitEntity instanceof org.bukkit.entity.EnderDragonPart) { + continue; + } + Entity craftEngineEntity = new BukkitEntity(bukkitEntity); + if (!craftEngineEntity.equals(entity) && predicate.test(craftEngineEntity)) { + entities.add(craftEngineEntity); + } + } + for (EnderDragonPart dragonPart : platformWorld().getEntitiesByClass(EnderDragonPart.class)) { + org.bukkit.util.BoundingBox partBoundingBox = dragonPart.getBoundingBox(); + boolean intersects = aabb.maxX >= partBoundingBox.getMinX() && + aabb.minX <= partBoundingBox.getMaxX() && + aabb.maxY >= partBoundingBox.getMinY() && + aabb.minY <= partBoundingBox.getMaxY() && + aabb.maxZ >= partBoundingBox.getMinZ() && + aabb.minZ <= partBoundingBox.getMaxZ(); + if (!intersects) continue; + Entity craftEnginePart = new BukkitEntity(dragonPart); + Entity craftEngineParent = new BukkitEntity(dragonPart.getParent()); + if (!craftEnginePart.equals(entity) && !craftEngineParent.equals(entity) && predicate.test(craftEnginePart)) { + entities.add(craftEnginePart); + } + } + return entities; + } + @Override public String name() { return platformWorld().getName(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java index 9a87bb5d9..39b79afb0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java @@ -6,13 +6,9 @@ public final class BlockKeys { private BlockKeys() {} // 特殊 public static final Key AIR = Key.of("minecraft:air"); - public static final Key NOTE_BLOCK = Key.of("minecraft:note_block"); public static final Key TRIPWIRE = Key.of("minecraft:tripwire"); public static final Key CACTUS = Key.of("minecraft:cactus"); public static final Key POWDER_SNOW = Key.of("minecraft:powder_snow"); - // 自然方块 - public static final Key OBSIDIAN = Key.of("minecraft:obsidian"); - public static final Key BEDROCK = Key.of("minecraft:bedrock"); // 功能方块 public static final Key CRAFTING_TABLE = Key.of("minecraft:crafting_table"); public static final Key STONECUTTER = Key.of("minecraft:stonecutter"); @@ -37,7 +33,6 @@ public final class BlockKeys { public static final Key WATER_CAULDRON = Key.of("minecraft:water_cauldron"); public static final Key BELL = Key.of("minecraft:bell"); public static final Key BEACON = Key.of("minecraft:beacon"); - public static final Key LODESTONE = Key.of("minecraft:lodestone"); public static final Key BEE_NEST = Key.of("minecraft:bee_nest"); public static final Key BEEHIVE = Key.of("minecraft:beehive"); public static final Key FLOWER_POT = Key.of("minecraft:flower_pot"); @@ -59,17 +54,59 @@ public final class BlockKeys { public static final Key TRIAL_SPAWNER = Key.of("minecraft:trial_spawner"); // 红石方块 public static final Key REDSTONE_WIRE = Key.of("minecraft:redstone_wire"); + public static final Key REDSTONE_TORCH = Key.of("minecraft:redstone_torch"); + public static final Key REDSTONE_BLOCK = Key.of("minecraft:redstone_block"); public static final Key REPEATER = Key.of("minecraft:repeater"); public static final Key COMPARATOR = Key.of("minecraft:comparator"); + public static final Key TARGET = Key.of("minecraft:target"); public static final Key LEVER = Key.of("minecraft:lever"); + public static final Key SCULK_SENSOR = Key.of("minecraft:sculk_sensor"); + public static final Key CALIBRATED_SCULK_SENSOR = Key.of("minecraft:calibrated_sculk_sensor"); + public static final Key TRIPWIRE_HOOK = Key.of("minecraft:tripwire_hook"); public static final Key DAYLIGHT_DETECTOR = Key.of("minecraft:daylight_detector"); + public static final Key LIGHTNING_ROD = Key.of("minecraft:lightning_rod"); public static final Key DISPENSER = Key.of("minecraft:dispenser"); public static final Key DROPPER = Key.of("minecraft:dropper"); public static final Key CRAFTER = Key.of("minecraft:crafter"); public static final Key HOPPER = Key.of("minecraft:hopper"); + public static final Key OBSERVER = Key.of("minecraft:observer"); + public static final Key NOTE_BLOCK = Key.of("minecraft:note_block"); + public static final Key DETECTOR_RAIL = Key.of("minecraft:detector_rail"); public static final Key TNT = Key.of("minecraft:tnt"); public static final Key REDSTONE_ORE = Key.of("minecraft:redstone_ore"); public static final Key DEEPSLATE_REDSTONE_ORE = Key.of("minecraft:deepslate_redstone_ore"); + // 按钮 + public static final Key OAK_BUTTON = Key.of("minecraft:oak_button"); + public static final Key SPRUCE_BUTTON = Key.of("minecraft:spruce_button"); + public static final Key BIRCH_BUTTON = Key.of("minecraft:birch_button"); + public static final Key JUNGLE_BUTTON = Key.of("minecraft:jungle_button"); + public static final Key ACACIA_BUTTON = Key.of("minecraft:acacia_button"); + public static final Key DARK_OAK_BUTTON = Key.of("minecraft:dark_oak_button"); + public static final Key MANGROVE_BUTTON = Key.of("minecraft:mangrove_button"); + public static final Key CHERRY_BUTTON = Key.of("minecraft:cherry_button"); + public static final Key PALE_OAK_BUTTON = Key.of("minecraft:pale_oak_button"); + public static final Key BAMBOO_BUTTON = Key.of("minecraft:bamboo_button"); + public static final Key CRIMSON_BUTTON = Key.of("minecraft:crimson_button"); + public static final Key WARPED_BUTTON = Key.of("minecraft:warped_button"); + public static final Key STONE_BUTTON = Key.of("minecraft:stone_button"); + public static final Key POLISHED_BLACKSTONE_BUTTON = Key.of("minecraft:polished_blackstone_button"); + // 压力板 + public static final Key OAK_PRESSURE_PLATE = Key.of("minecraft:oak_pressure_plate"); + public static final Key SPRUCE_PRESSURE_PLATE = Key.of("minecraft:spruce_pressure_plate"); + public static final Key BIRCH_PRESSURE_PLATE = Key.of("minecraft:birch_pressure_plate"); + public static final Key JUNGLE_PRESSURE_PLATE = Key.of("minecraft:jungle_pressure_plate"); + public static final Key ACACIA_PRESSURE_PLATE = Key.of("minecraft:acacia_pressure_plate"); + public static final Key DARK_OAK_PRESSURE_PLATE = Key.of("minecraft:dark_oak_pressure_plate"); + public static final Key MANGROVE_PRESSURE_PLATE = Key.of("minecraft:mangrove_pressure_plate"); + public static final Key CHERRY_PRESSURE_PLATE = Key.of("minecraft:cherry_pressure_plate"); + public static final Key PALE_OAK_PRESSURE_PLATE = Key.of("minecraft:pale_oak_pressure_plate"); + public static final Key BAMBOO_PRESSURE_PLATE = Key.of("minecraft:bamboo_pressure_plate"); + public static final Key CRIMSON_PRESSURE_PLATE = Key.of("minecraft:crimson_pressure_plate"); + public static final Key WARPED_PRESSURE_PLATE = Key.of("minecraft:warped_pressure_plate"); + public static final Key STONE_PRESSURE_PLATE = Key.of("minecraft:stone_pressure_plate"); + public static final Key POLISHED_BLACKSTONE_PRESSURE_PLATE = Key.of("minecraft:polished_blackstone_pressure_plate"); + public static final Key LIGHT_WEIGHTED_PRESSURE_PLATE = Key.of("minecraft:light_weighted_pressure_plate"); + public static final Key HEAVY_WEIGHTED_PRESSURE_PLATE = Key.of("minecraft:heavy_weighted_pressure_plate"); // 管理员用品 public static final Key COMMAND_BLOCK = Key.of("minecraft:command_block"); public static final Key CHAIN_COMMAND_BLOCK = Key.of("minecraft:chain_command_block"); @@ -79,6 +116,65 @@ public final class BlockKeys { public static final Key TEST_INSTANCE_BLOCK = Key.of("minecraft:test_instance_block"); public static final Key TEST_BLOCK = Key.of("minecraft:test_block"); public static final Key LIGHT = Key.of("minecraft:light"); + // 门 + public static final Key OAK_DOOR = Key.of("minecraft:oak_door"); + public static final Key SPRUCE_DOOR = Key.of("minecraft:spruce_door"); + public static final Key BIRCH_DOOR = Key.of("minecraft:birch_door"); + public static final Key JUNGLE_DOOR = Key.of("minecraft:jungle_door"); + public static final Key ACACIA_DOOR = Key.of("minecraft:acacia_door"); + public static final Key DARK_OAK_DOOR = Key.of("minecraft:dark_oak_door"); + public static final Key MANGROVE_DOOR = Key.of("minecraft:mangrove_door"); + public static final Key CHERRY_DOOR = Key.of("minecraft:cherry_door"); + public static final Key PALE_OAK_DOOR = Key.of("minecraft:pale_oak_door"); + public static final Key BAMBOO_DOOR = Key.of("minecraft:bamboo_door"); + public static final Key CRIMSON_DOOR = Key.of("minecraft:crimson_door"); + public static final Key WARPED_DOOR = Key.of("minecraft:warped_door"); + public static final Key IRON_DOOR = Key.of("minecraft:iron_door"); + + public static final Key COPPER_DOOR = Key.of("minecraft:copper_door"); + public static final Key EXPOSED_COPPER_DOOR = Key.of("minecraft:exposed_copper_door"); + public static final Key WEATHERED_COPPER_DOOR = Key.of("minecraft:weathered_copper_door"); + public static final Key OXIDIZED_COPPER_DOOR = Key.of("minecraft:oxidized_copper_door"); + public static final Key WAXED_COPPER_DOOR = Key.of("minecraft:waxed_copper_door"); + public static final Key WAXED_EXPOSED_COPPER_DOOR = Key.of("minecraft:waxed_exposed_copper_door"); + public static final Key WAXED_WEATHERED_COPPER_DOOR = Key.of("minecraft:waxed_weathered_copper_door"); + public static final Key WAXED_OXIDIZED_COPPER_DOOR = Key.of("minecraft:waxed_oxidized_copper_door"); + // 活板门 + public static final Key OAK_TRAPDOOR = Key.of("minecraft:oak_trapdoor"); + public static final Key SPRUCE_TRAPDOOR = Key.of("minecraft:spruce_trapdoor"); + public static final Key BIRCH_TRAPDOOR = Key.of("minecraft:birch_trapdoor"); + public static final Key JUNGLE_TRAPDOOR = Key.of("minecraft:jungle_trapdoor"); + public static final Key ACACIA_TRAPDOOR = Key.of("minecraft:acacia_trapdoor"); + public static final Key DARK_OAK_TRAPDOOR = Key.of("minecraft:dark_oak_trapdoor"); + public static final Key MANGROVE_TRAPDOOR = Key.of("minecraft:mangrove_trapdoor"); + public static final Key CHERRY_TRAPDOOR = Key.of("minecraft:cherry_trapdoor"); + public static final Key PALE_OAK_TRAPDOOR = Key.of("minecraft:pale_oak_trapdoor"); + public static final Key BAMBOO_TRAPDOOR = Key.of("minecraft:bamboo_trapdoor"); + public static final Key CRIMSON_TRAPDOOR = Key.of("minecraft:crimson_trapdoor"); + public static final Key WARPED_TRAPDOOR = Key.of("minecraft:warped_trapdoor"); + public static final Key IRON_TRAPDOOR = Key.of("minecraft:iron_trapdoor"); + + public static final Key COPPER_TRAPDOOR = Key.of("minecraft:copper_trapdoor"); + public static final Key EXPOSED_COPPER_TRAPDOOR = Key.of("minecraft:exposed_copper_trapdoor"); + public static final Key WEATHERED_COPPER_TRAPDOOR = Key.of("minecraft:weathered_copper_trapdoor"); + public static final Key OXIDIZED_COPPER_TRAPDOOR = Key.of("minecraft:oxidized_copper_trapdoor"); + public static final Key WAXED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_copper_trapdoor"); + public static final Key WAXED_EXPOSED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_exposed_copper_trapdoor"); + public static final Key WAXED_WEATHERED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_weathered_copper_trapdoor"); + public static final Key WAXED_OXIDIZED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_oxidized_copper_trapdoor"); + // 栅栏门 + public static final Key OAK_FENCE_GATE = Key.of("minecraft:oak_fence_gate"); + public static final Key SPRUCE_FENCE_GATE = Key.of("minecraft:spruce_fence_gate"); + public static final Key BIRCH_FENCE_GATE = Key.of("minecraft:birch_fence_gate"); + public static final Key JUNGLE_FENCE_GATE = Key.of("minecraft:jungle_fence_gate"); + public static final Key ACACIA_FENCE_GATE = Key.of("minecraft:acacia_fence_gate"); + public static final Key DARK_OAK_FENCE_GATE = Key.of("minecraft:dark_oak_fence_gate"); + public static final Key MANGROVE_FENCE_GATE = Key.of("minecraft:mangrove_fence_gate"); + public static final Key CHERRY_FENCE_GATE = Key.of("minecraft:cherry_fence_gate"); + public static final Key PALE_OAK_FENCE_GATE = Key.of("minecraft:pale_oak_fence_gate"); + public static final Key BAMBOO_FENCE_GATE = Key.of("minecraft:bamboo_fence_gate"); + public static final Key CRIMSON_FENCE_GATE = Key.of("minecraft:crimson_fence_gate"); + public static final Key WARPED_FENCE_GATE = Key.of("minecraft:warped_fence_gate"); // 床 public static final Key WHITE_BED = Key.of("minecraft:white_bed"); public static final Key LIGHT_GRAY_BED = Key.of("minecraft:light_gray_bed"); @@ -151,80 +247,6 @@ public final class BlockKeys { public static final Key PURPLE_SHULKER_BOX = Key.of("minecraft:purple_shulker_box"); public static final Key MAGENTA_SHULKER_BOX = Key.of("minecraft:magenta_shulker_box"); public static final Key PINK_SHULKER_BOX = Key.of("minecraft:pink_shulker_box"); - // 按钮 - public static final Key OAK_BUTTON = Key.of("minecraft:oak_button"); - public static final Key SPRUCE_BUTTON = Key.of("minecraft:spruce_button"); - public static final Key BIRCH_BUTTON = Key.of("minecraft:birch_button"); - public static final Key JUNGLE_BUTTON = Key.of("minecraft:jungle_button"); - public static final Key ACACIA_BUTTON = Key.of("minecraft:acacia_button"); - public static final Key DARK_OAK_BUTTON = Key.of("minecraft:dark_oak_button"); - public static final Key MANGROVE_BUTTON = Key.of("minecraft:mangrove_button"); - public static final Key CHERRY_BUTTON = Key.of("minecraft:cherry_button"); - public static final Key PALE_OAK_BUTTON = Key.of("minecraft:pale_oak_button"); - public static final Key BAMBOO_BUTTON = Key.of("minecraft:bamboo_button"); - public static final Key CRIMSON_BUTTON = Key.of("minecraft:crimson_button"); - public static final Key WARPED_BUTTON = Key.of("minecraft:warped_button"); - public static final Key STONE_BUTTON = Key.of("minecraft:stone_button"); - public static final Key POLISHED_BLACKSTONE_BUTTON = Key.of("minecraft:polished_blackstone_button"); - // 门 - public static final Key OAK_DOOR = Key.of("minecraft:oak_door"); - public static final Key SPRUCE_DOOR = Key.of("minecraft:spruce_door"); - public static final Key BIRCH_DOOR = Key.of("minecraft:birch_door"); - public static final Key JUNGLE_DOOR = Key.of("minecraft:jungle_door"); - public static final Key ACACIA_DOOR = Key.of("minecraft:acacia_door"); - public static final Key DARK_OAK_DOOR = Key.of("minecraft:dark_oak_door"); - public static final Key MANGROVE_DOOR = Key.of("minecraft:mangrove_door"); - public static final Key CHERRY_DOOR = Key.of("minecraft:cherry_door"); - public static final Key PALE_OAK_DOOR = Key.of("minecraft:pale_oak_door"); - public static final Key BAMBOO_DOOR = Key.of("minecraft:bamboo_door"); - public static final Key CRIMSON_DOOR = Key.of("minecraft:crimson_door"); - public static final Key WARPED_DOOR = Key.of("minecraft:warped_door"); - public static final Key IRON_DOOR = Key.of("minecraft:iron_door"); - - public static final Key COPPER_DOOR = Key.of("minecraft:copper_door"); - public static final Key EXPOSED_COPPER_DOOR = Key.of("minecraft:exposed_copper_door"); - public static final Key WEATHERED_COPPER_DOOR = Key.of("minecraft:weathered_copper_door"); - public static final Key OXIDIZED_COPPER_DOOR = Key.of("minecraft:oxidized_copper_door"); - public static final Key WAXED_COPPER_DOOR = Key.of("minecraft:waxed_copper_door"); - public static final Key WAXED_EXPOSED_COPPER_DOOR = Key.of("minecraft:waxed_exposed_copper_door"); - public static final Key WAXED_WEATHERED_COPPER_DOOR = Key.of("minecraft:waxed_weathered_copper_door"); - public static final Key WAXED_OXIDIZED_COPPER_DOOR = Key.of("minecraft:waxed_oxidized_copper_door"); - // 活板门 - public static final Key OAK_TRAPDOOR = Key.of("minecraft:oak_trapdoor"); - public static final Key SPRUCE_TRAPDOOR = Key.of("minecraft:spruce_trapdoor"); - public static final Key BIRCH_TRAPDOOR = Key.of("minecraft:birch_trapdoor"); - public static final Key JUNGLE_TRAPDOOR = Key.of("minecraft:jungle_trapdoor"); - public static final Key ACACIA_TRAPDOOR = Key.of("minecraft:acacia_trapdoor"); - public static final Key DARK_OAK_TRAPDOOR = Key.of("minecraft:dark_oak_trapdoor"); - public static final Key MANGROVE_TRAPDOOR = Key.of("minecraft:mangrove_trapdoor"); - public static final Key CHERRY_TRAPDOOR = Key.of("minecraft:cherry_trapdoor"); - public static final Key PALE_OAK_TRAPDOOR = Key.of("minecraft:pale_oak_trapdoor"); - public static final Key BAMBOO_TRAPDOOR = Key.of("minecraft:bamboo_trapdoor"); - public static final Key CRIMSON_TRAPDOOR = Key.of("minecraft:crimson_trapdoor"); - public static final Key WARPED_TRAPDOOR = Key.of("minecraft:warped_trapdoor"); - public static final Key IRON_TRAPDOOR = Key.of("minecraft:iron_trapdoor"); - - public static final Key COPPER_TRAPDOOR = Key.of("minecraft:copper_trapdoor"); - public static final Key EXPOSED_COPPER_TRAPDOOR = Key.of("minecraft:exposed_copper_trapdoor"); - public static final Key WEATHERED_COPPER_TRAPDOOR = Key.of("minecraft:weathered_copper_trapdoor"); - public static final Key OXIDIZED_COPPER_TRAPDOOR = Key.of("minecraft:oxidized_copper_trapdoor"); - public static final Key WAXED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_copper_trapdoor"); - public static final Key WAXED_EXPOSED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_exposed_copper_trapdoor"); - public static final Key WAXED_WEATHERED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_weathered_copper_trapdoor"); - public static final Key WAXED_OXIDIZED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_oxidized_copper_trapdoor"); - // 栅栏门 - public static final Key OAK_FENCE_GATE = Key.of("minecraft:oak_fence_gate"); - public static final Key SPRUCE_FENCE_GATE = Key.of("minecraft:spruce_fence_gate"); - public static final Key BIRCH_FENCE_GATE = Key.of("minecraft:birch_fence_gate"); - public static final Key JUNGLE_FENCE_GATE = Key.of("minecraft:jungle_fence_gate"); - public static final Key ACACIA_FENCE_GATE = Key.of("minecraft:acacia_fence_gate"); - public static final Key DARK_OAK_FENCE_GATE = Key.of("minecraft:dark_oak_fence_gate"); - public static final Key MANGROVE_FENCE_GATE = Key.of("minecraft:mangrove_fence_gate"); - public static final Key CHERRY_FENCE_GATE = Key.of("minecraft:cherry_fence_gate"); - public static final Key PALE_OAK_FENCE_GATE = Key.of("minecraft:pale_oak_fence_gate"); - public static final Key BAMBOO_FENCE_GATE = Key.of("minecraft:bamboo_fence_gate"); - public static final Key CRIMSON_FENCE_GATE = Key.of("minecraft:crimson_fence_gate"); - public static final Key WARPED_FENCE_GATE = Key.of("minecraft:warped_fence_gate"); // 告示牌 public static final Key OAK_SIGN = Key.of("minecraft:oak_sign"); public static final Key SPRUCE_SIGN = Key.of("minecraft:spruce_sign"); @@ -277,4 +299,21 @@ public final class BlockKeys { public static final Key BAMBOO_WALL_HANGING_SIGN = Key.of("minecraft:bamboo_wall_hanging_sign"); public static final Key CRIMSON_WALL_HANGING_SIGN = Key.of("minecraft:crimson_wall_hanging_sign"); public static final Key WARPED_WALL_HANGING_SIGN = Key.of("minecraft:warped_wall_hanging_sign"); + + public static final Key[] BUTTONS = new Key[]{ + OAK_BUTTON, SPRUCE_BUTTON, BIRCH_BUTTON, JUNGLE_BUTTON, ACACIA_BUTTON, DARK_OAK_BUTTON, MANGROVE_BUTTON, CHERRY_BUTTON, + PALE_OAK_BUTTON, BAMBOO_BUTTON, CRIMSON_BUTTON, WARPED_BUTTON, STONE_BUTTON, POLISHED_BLACKSTONE_BUTTON + }; + + public static final Key[] PRESSURE_PLATES = new Key[]{ + OAK_PRESSURE_PLATE, SPRUCE_PRESSURE_PLATE, BIRCH_PRESSURE_PLATE, JUNGLE_PRESSURE_PLATE, ACACIA_PRESSURE_PLATE, + DARK_OAK_PRESSURE_PLATE, MANGROVE_PRESSURE_PLATE, CHERRY_PRESSURE_PLATE, PALE_OAK_PRESSURE_PLATE, BAMBOO_PRESSURE_PLATE, + CRIMSON_PRESSURE_PLATE, WARPED_PRESSURE_PLATE, STONE_PRESSURE_PLATE, POLISHED_BLACKSTONE_PRESSURE_PLATE, + LIGHT_WEIGHTED_PRESSURE_PLATE, HEAVY_WEIGHTED_PRESSURE_PLATE + }; + + public static final Key[] REDSTONE_CONNECTION = new Key[] { + REDSTONE_WIRE, REDSTONE_TORCH, REDSTONE_BLOCK, REPEATER, COMPARATOR, TARGET, LEVER, SCULK_SENSOR, CALIBRATED_SCULK_SENSOR, + TRIPWIRE_HOOK, LECTERN, DAYLIGHT_DETECTOR, LIGHTNING_ROD, TRAPPED_CHEST, JUKEBOX, OBSERVER, DETECTOR_RAIL + }; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ArrayUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ArrayUtils.java index da87a2c53..5f060ad46 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ArrayUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ArrayUtils.java @@ -1,10 +1,7 @@ package net.momirealms.craftengine.core.util; import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; public class ArrayUtils { @@ -77,6 +74,18 @@ public class ArrayUtils { .split(","); } + public static boolean contains(T[] array, T element) { + if (array == null || element == null) { + return false; + } + for (T item : array) { + if (Objects.equals(item, element)) { + return true; + } + } + return false; + } + public static boolean isEmpty(Object[] array) { return array == null || array.length == 0; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java index 6d9e96b95..16594275a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java @@ -57,21 +57,6 @@ public record Key(String namespace, String value) { return this.value.equals(key.value()) && this.namespace.equals(key.namespace()); } - public boolean in(Key... items) { - if (items == null) { - return false; - } - for (Key key : items) { - if (key == this) { - return true; - } - if (this.value.equals(key.value()) && this.namespace.equals(key.namespace())) { - return true; - } - } - return false; - } - @Override public @NotNull String toString() { return asString(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index a7d960454..6dbd9cce0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -1,17 +1,22 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.particle.ParticleData; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.nio.file.Path; +import java.util.List; import java.util.UUID; +import java.util.function.Predicate; public interface World { @@ -29,6 +34,18 @@ public interface World { void setBlockAt(int x, int y, int z, BlockStateWrapper blockState, int flags); + List getEntities(@Nullable Entity entity, AABB aabb, Predicate predicate); + + default List getEntities(@Nullable Entity entity, AABB aabb) { + Predicate noSpectator = player -> { + if (player instanceof Player) { + return !((Player) player).isSpectatorMode(); + } + return true; + }; + return this.getEntities(entity, aabb, noSpectator); + } + String name(); Path directory();