9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-30 04:19:27 +00:00

稍微改进一下

This commit is contained in:
XiaoMoMi
2025-07-26 17:40:29 +08:00
parent ddb79bd6f8
commit 14c30982f7
14 changed files with 86 additions and 63 deletions

View File

@@ -77,6 +77,7 @@ public class ItemEventListener implements Listener {
if (ItemUtils.isEmpty(itemInHand)) return;
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem();
if (optionalCustomItem.isEmpty()) return;
// 如果目标实体与手中物品可以产生交互,那么忽略
if (InteractUtils.isEntityInteractable(player, entity, itemInHand)) return;
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
@@ -267,27 +268,7 @@ public class ItemEventListener implements Listener {
}
}
// execute item right click functions
if (hasCustomItem) {
Cancellable dummy = Cancellable.dummy();
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
.withOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState)
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation()))
.withParameter(DirectContextParameters.HAND, hand)
.withParameter(DirectContextParameters.EVENT, dummy)
);
CustomItem<ItemStack> customItem = optionalCustomItem.get();
if (!(InteractUtils.isInteractable(player, blockData, hitResult, itemInHand) && !player.isSneaking())) {
customItem.execute(context, EventTrigger.RIGHT_CLICK);
}
if (dummy.isCancelled()) {
event.setCancelled(true);
return;
}
}
// 优先检查物品行为,再执行自定义事件
// 检查其他的物品行为,物品行为理论只在交互时处理
Optional<List<ItemBehavior>> optionalItemBehaviors = itemInHand.getItemBehavior();
// 物品类型是否包含自定义物品行为,行为不一定来自于自定义物品,部分原版物品也包含了新的行为
@@ -315,8 +296,31 @@ public class ItemEventListener implements Listener {
}
}
}
// 执行物品右键事件
if (hasCustomItem) {
// 要求服务端侧这个方块不可交互,或玩家处于潜行状态
if (serverPlayer.isSecondaryUseActive() || !InteractUtils.isInteractable(player, blockData, hitResult, itemInHand)) {
Cancellable dummy = Cancellable.dummy();
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
.withOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState)
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation()))
.withParameter(DirectContextParameters.HAND, hand)
.withParameter(DirectContextParameters.EVENT, dummy)
);
CustomItem<ItemStack> customItem = optionalCustomItem.get();
customItem.execute(context, EventTrigger.RIGHT_CLICK);
if (dummy.isCancelled()) {
event.setCancelled(true);
return;
}
}
}
}
// 执行物品左键事件
if (hasCustomItem && action == Action.LEFT_CLICK_BLOCK) {
Cancellable dummy = Cancellable.dummy();
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.plugin.classpath;
import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender;
import net.momirealms.craftengine.core.plugin.classpath.URLClassLoaderAccess;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import org.bukkit.Bukkit;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
@@ -20,18 +21,20 @@ public class PaperClassPathAppender implements ClassPathAppender {
private final URLClassLoaderAccess classLoaderAccess;
public PaperClassPathAppender(ClassLoader classLoader) {
try {
if (clazz$PaperPluginClassLoader != null && clazz$PaperPluginClassLoader.isInstance(classLoader)) {
URLClassLoader libraryClassLoader = (URLClassLoader) field$PaperPluginClassLoader$libraryLoader.get(classLoader);
this.classLoaderAccess = URLClassLoaderAccess.create(libraryClassLoader);
} else if (classLoader instanceof URLClassLoader) {
this.classLoaderAccess = URLClassLoaderAccess.create((URLClassLoader) classLoader);
} else {
throw new IllegalStateException("ClassLoader is not instance of URLClassLoader");
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to instantiate PaperPluginClassLoader", e);
}
// 25/7/26 往Bukkit类加载器里硬灌就能保证库也被其他插件使用了
this.classLoaderAccess = URLClassLoaderAccess.create((URLClassLoader) Bukkit.class.getClassLoader());
// try {
// if (clazz$PaperPluginClassLoader != null && clazz$PaperPluginClassLoader.isInstance(classLoader)) {
// URLClassLoader libraryClassLoader = (URLClassLoader) field$PaperPluginClassLoader$libraryLoader.get(classLoader);
// this.classLoaderAccess = URLClassLoaderAccess.create(libraryClassLoader);
// } else if (classLoader instanceof URLClassLoader) {
// this.classLoaderAccess = URLClassLoaderAccess.create((URLClassLoader) classLoader);
// } else {
// throw new IllegalStateException("ClassLoader is not instance of URLClassLoader");
// }
// } catch (ReflectiveOperationException e) {
// throw new RuntimeException("Failed to instantiate PaperPluginClassLoader", e);
// }
}
@Override

View File

@@ -6,7 +6,9 @@ import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import java.util.function.Consumer;

View File

@@ -4,6 +4,8 @@ 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.recipe.BukkitRecipeManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.core.block.BlockKeys;
import net.momirealms.craftengine.core.entity.EntityTypeKeys;
import net.momirealms.craftengine.core.item.Item;
@@ -28,7 +30,10 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class InteractUtils {
private static final Map<Key, QuadFunction<Player, Item<ItemStack>, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>();
@@ -67,11 +72,15 @@ public class InteractUtils {
registerInteraction(BlockKeys.TEST_BLOCK, (player, item, blockState, result) -> player.isOp() && player.getGameMode() == GameMode.CREATIVE);
registerInteraction(BlockKeys.LIGHT, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.LIGHT));
registerInteraction(BlockKeys.LODESTONE, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.COMPASS));
registerInteraction(BlockKeys.BEE_NEST, (player, item, blockState, result) -> Set.of(ItemKeys.SHEARS, ItemKeys.GLASS_BOTTLE).contains(item.vanillaId()));
registerInteraction(BlockKeys.BEEHIVE, (player, item, blockState, result) -> Set.of(ItemKeys.SHEARS, ItemKeys.GLASS_BOTTLE).contains(item.vanillaId()));
registerInteraction(BlockKeys.BEE_NEST, (player, item, blockState, result) -> {
Key id = item.vanillaId();
return ItemKeys.SHEARS.equals(id) || ItemKeys.GLASS_BOTTLE.equals(id);
});
registerInteraction(BlockKeys.BEEHIVE, (player, item, blockState, result) -> {
Key id = item.vanillaId();
return ItemKeys.SHEARS.equals(id) || ItemKeys.GLASS_BOTTLE.equals(id);
});
registerInteraction(BlockKeys.POWDER_SNOW, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.BUCKET));
registerWillConsume(BlockKeys.CAULDRON, (player, item, blockState, result) -> Set.of(ItemKeys.WATER_BUCKET, ItemKeys.LAVA_BUCKET).contains(item.vanillaId()));
registerWillConsume(BlockKeys.LAVA_CAULDRON, (player, item, blockState, result) -> Set.of(ItemKeys.BUCKET, ItemKeys.WATER_BUCKET, ItemKeys.LAVA_BUCKET).contains(item.vanillaId()));
registerInteraction(BlockKeys.REDSTONE_ORE, (player, item, blockState, result) -> {
Optional<List<ItemBehavior>> behaviors = item.getItemBehavior();
if (behaviors.isPresent()) {
@@ -90,11 +99,7 @@ public class InteractUtils {
}
return true;
});
registerWillConsume(BlockKeys.WATER_CAULDRON, (player, item, blockState, result) -> {
if (blockState instanceof Levelled levelled && levelled.getLevel() == levelled.getMaximumLevel())
return item.vanillaId().equals(ItemKeys.BUCKET);
return Set.of(ItemKeys.GLASS_BOTTLE, ItemKeys.WATER_BUCKET, ItemKeys.LAVA_BUCKET).contains(item.vanillaId());
});
registerInteraction(BlockKeys.BELL, (player, item, blockState, result) -> {
Direction direction = result.getDirection();
BlockPos pos = result.getBlockPos();
@@ -327,6 +332,20 @@ public class InteractUtils {
static {
registerWillConsume(BlockKeys.CACTUS, (player, item, blockState, result) ->
result.getDirection() == Direction.UP && item.id().equals(ItemKeys.CACTUS));
registerWillConsume(BlockKeys.CAULDRON, (player, item, blockState, result) -> {
Key id = item.vanillaId();
return ItemKeys.WATER_BUCKET.equals(id) || ItemKeys.LAVA_BUCKET.equals(id);
});
registerWillConsume(BlockKeys.LAVA_CAULDRON, (player, item, blockState, result) -> {
Key id = item.vanillaId();
return ItemKeys.BUCKET.equals(id) || ItemKeys.LAVA_BUCKET.equals(id) || ItemKeys.WATER_BUCKET.equals(id);
});
registerWillConsume(BlockKeys.WATER_CAULDRON, (player, item, blockState, result) -> {
if (blockState instanceof Levelled levelled && levelled.getLevel() == levelled.getMaximumLevel())
return item.vanillaId().equals(ItemKeys.BUCKET);
Key id = item.vanillaId();
return ItemKeys.GLASS_BOTTLE.equals(id) || ItemKeys.WATER_BUCKET.equals(id) || ItemKeys.LAVA_BUCKET.equals(id);
});
}
static {
@@ -466,8 +485,10 @@ public class InteractUtils {
}
public static boolean isEntityInteractable(Player player, Entity entity, @Nullable Item<ItemStack> item) {
Key key = Key.of(String.valueOf(entity.getType()));
TriFunction<Player, Entity, Item<ItemStack>, Boolean> func = ENTITY_INTERACTIONS.get(key);
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(entity);
Object entityType = FastNMS.INSTANCE.method$Entity$getType(nmsEntity);
Object id = FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ENTITY_TYPE, entityType);
TriFunction<Player, Entity, Item<ItemStack>, Boolean> func = ENTITY_INTERACTIONS.get(KeyUtils.resourceLocationToKey(id));
return func != null && func.apply(player, entity, item);
}

View File

@@ -3,11 +3,6 @@ package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag;
import java.util.HashMap;
import java.util.Map;