From 2d9370615e7c6b1b782b341d75110cc8ae61ae86 Mon Sep 17 00:00:00 2001 From: halogly Date: Wed, 16 Jul 2025 18:22:07 +0800 Subject: [PATCH 01/83] Improve entity and block interaction handling Added checks for interactable entities and blocks, including chiseled bookshelf, redstone ore, and deepslate redstone ore. Updated ItemEventListener to use new InteractUtils methods for entity and block interactions, preventing custom item execution on interactable entities and blocks. --- .../item/listener/ItemEventListener.java | 33 ++++++++------ .../bukkit/util/InteractUtils.java | 44 ++++++++++++++++++- .../craftengine/core/block/BlockKeys.java | 3 ++ 3 files changed, 66 insertions(+), 14 deletions(-) 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 b10dd7ad7..b507b3b6f 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 @@ -36,6 +36,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -66,6 +67,8 @@ public class ItemEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onInteractEntity(PlayerInteractEntityEvent event) { + Player player = event.getPlayer(); + Entity entity = event.getRightClicked(); BukkitServerPlayer serverPlayer = this.plugin.adapt(event.getPlayer()); if (serverPlayer == null) return; InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; @@ -75,15 +78,17 @@ public class ItemEventListener implements Listener { Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isEmpty()) return; - Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) - .withParameter(DirectContextParameters.HAND, hand) - ); - CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.RIGHT_CLICK); + if (!InteractUtils.isEntityInteractable(player, entity, itemInHand)) { + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) + .withParameter(DirectContextParameters.HAND, hand) + ); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.RIGHT_CLICK); + } } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @@ -275,10 +280,12 @@ public class ItemEventListener implements Listener { .withParameter(DirectContextParameters.EVENT, dummy) ); CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.RIGHT_CLICK); - if (dummy.isCancelled()) { - event.setCancelled(true); - return; + if (!InteractUtils.isInteractable(player, blockData, hitResult, null)) { + customItem.execute(context, EventTrigger.RIGHT_CLICK); + if (dummy.isCancelled()) { + event.setCancelled(true); + return; + } } } 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 11f5213b8..281b1ed0f 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 @@ -16,12 +16,14 @@ import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bell; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; +import org.bukkit.entity.minecart.RideableMinecart; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.Set; public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); @@ -88,6 +90,7 @@ public class InteractUtils { item.recipeIngredientId(), item ))) != null; }); + registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DISPENSER, (player, item, blockState, result) -> true); @@ -267,6 +270,8 @@ public class InteractUtils { registerInteraction(BlockKeys.REPEATING_COMMAND_BLOCK, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.CHAIN_COMMAND_BLOCK, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.COMMAND_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.REDSTONE_ORE, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.DEEPSLATE_REDSTONE_ORE, (player, item, blockState, result) -> true); } static { @@ -274,6 +279,27 @@ public class InteractUtils { result.getDirection() == Direction.UP && item.id().equals(ItemKeys.CACTUS)); } + private static final Set INTERACTABLE_ENTITIES = Set.of( + EntityType.ALLAY, + EntityType.HORSE, + EntityType.ZOMBIE_HORSE, + EntityType.SKELETON_HORSE, + EntityType.DONKEY, + EntityType.MULE, + EntityType.VILLAGER, + EntityType.WANDERING_TRADER, + EntityType.LLAMA, + EntityType.TRADER_LLAMA, + EntityType.CAMEL, + EntityType.CHEST_MINECART, + EntityType.FURNACE_MINECART, + EntityType.HOPPER_MINECART, + EntityType.COMMAND_BLOCK_MINECART, + EntityType.ITEM_FRAME, + EntityType.GLOW_ITEM_FRAME, + EntityType.HAPPY_GHAST + ); + private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { var previous = INTERACTIONS.put(key, function); if (previous != null) { @@ -297,6 +323,22 @@ public class InteractUtils { } } + public static boolean isEntityInteractable(Player player, Entity entity, Item item) { + boolean isSneaking = player.isSneaking(); + if (entity.getType() == EntityType.PIGLIN && + item != null && + item.vanillaId().equals(Key.of("minecraft:gold_ingot"))) { + return true; + } + return switch (entity) { + case ChestBoat ignored -> true; + case Boat ignored -> !isSneaking; + case RideableMinecart ignored -> !isSneaking; + case Steerable steerable -> !isSneaking && steerable.hasSaddle(); + default -> INTERACTABLE_ENTITIES.contains(entity.getType()); + }; + } + 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/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java index fba210d01..4e377f7d2 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 @@ -42,6 +42,9 @@ public final class BlockKeys { public static final Key CHAIN_COMMAND_BLOCK = Key.of("minecraft:chain_command_block"); public static final Key REPEATING_COMMAND_BLOCK = Key.of("minecraft:repeating_command_block"); public static final Key DECORATED_POT = Key.of("minecraft:decorated_pot"); + public static final Key CHISELED_BOOKSHELF = Key.of("minecraft:chiseled_bookshelf"); + 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 CAKE = Key.of("minecraft:cake"); public static final Key CANDLE_CAKE = Key.of("minecraft:candle_cake"); From 348f004500e910c231d3d21a4b8e3fc132a62d1b Mon Sep 17 00:00:00 2001 From: halogly Date: Fri, 18 Jul 2025 13:42:49 +0800 Subject: [PATCH 02/83] Add support for Happy Ghast and harness interactions Introduces logic for handling Happy Ghast entity interactions and harness item tags, gated by Minecraft version 1.21.6. Refactors entity and block interaction checks to use new utility methods and dynamic entity sets, improving maintainability and future compatibility. --- .../item/listener/ItemEventListener.java | 17 ++++---- .../craftengine/bukkit/util/EntityUtils.java | 29 +++++++++++-- .../bukkit/util/InteractUtils.java | 43 ++++++++++++++----- .../craftengine/bukkit/util/ItemTags.java | 15 +++++++ 4 files changed, 81 insertions(+), 23 deletions(-) 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 b507b3b6f..8f2095acf 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 @@ -34,6 +34,8 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.ChiseledBookshelf; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; import org.bukkit.entity.Entity; @@ -53,10 +55,7 @@ import org.bukkit.inventory.EnchantingInventory; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; public class ItemEventListener implements Listener { private final BukkitCraftEngine plugin; @@ -280,12 +279,12 @@ public class ItemEventListener implements Listener { .withParameter(DirectContextParameters.EVENT, dummy) ); CustomItem customItem = optionalCustomItem.get(); - if (!InteractUtils.isInteractable(player, blockData, hitResult, null)) { + if (!InteractUtils.isInteractable(player, blockData, hitResult, itemInHand) && !player.isSneaking()) { customItem.execute(context, EventTrigger.RIGHT_CLICK); - if (dummy.isCancelled()) { - event.setCancelled(true); - return; - } + } + if (dummy.isCancelled()) { + event.setCancelled(true); + return; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index 30fd6fa4b..0dfe4ec0d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -2,14 +2,17 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.util.Key; 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.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; import java.util.function.Consumer; @@ -34,4 +37,24 @@ public class EntityUtils { return LegacyEntityUtils.spawnEntity(world, loc, type, function); } } + + public static boolean isPiglinWithGoldIngot(Entity entity, Item item) { + return entity.getType() == EntityType.PIGLIN && + item != null && + item.vanillaId().equals(Key.of("minecraft:gold_ingot")); + } + + public static boolean isHappyGhastRideable(Entity entity) { + if (!VersionHelper.isOrAbove1_21_6() && + !entity.getType().name().equals("HAPPY_GHAST")) return false; + return entity instanceof LivingEntity livingEntity + && livingEntity.getEquipment() != null + && hasHarness(livingEntity.getEquipment()); + } + + public static boolean hasHarness(EntityEquipment equipment) { + ItemStack bodyItem = equipment.getItem(EquipmentSlot.BODY); + return ItemTags.ITEMS_HARNESSES != null && + ItemTags.ITEMS_HARNESSES.isTagged(bodyItem.getType()); + } } 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 281b1ed0f..54e1aba40 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 @@ -12,23 +12,25 @@ 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.VersionHelper; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bell; +import org.bukkit.block.data.type.ChiseledBookshelf; import org.bukkit.entity.*; import org.bukkit.entity.minecart.RideableMinecart; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import java.lang.reflect.Field; +import java.util.*; public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); private static final Map, BlockData, BlockHitResult, Boolean>> WILL_CONSUME = new HashMap<>(); private static final Key NOTE_BLOCK_TOP_INSTRUMENTS = Key.of("minecraft:noteblock_top_instruments"); + private static final Set INTERACTABLE_ENTITIES = createInteractableEntities(); private InteractUtils() {} @@ -90,7 +92,15 @@ public class InteractUtils { item.recipeIngredientId(), item ))) != null; }); - registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> { + Direction direction = result.getDirection(); + if (player.isSneaking()) return false; + if (blockState instanceof ChiseledBookshelf chiseledBookshelf) { + Direction facing = DirectionUtils.toDirection(chiseledBookshelf.getFacing()); + return facing == direction; + } + return false; + }); registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DISPENSER, (player, item, blockState, result) -> true); @@ -279,7 +289,9 @@ public class InteractUtils { result.getDirection() == Direction.UP && item.id().equals(ItemKeys.CACTUS)); } - private static final Set INTERACTABLE_ENTITIES = Set.of( + private static Set createInteractableEntities() { + Set set = EnumSet.noneOf(EntityType.class); + set.addAll(Set.of( EntityType.ALLAY, EntityType.HORSE, EntityType.ZOMBIE_HORSE, @@ -296,9 +308,17 @@ public class InteractUtils { EntityType.HOPPER_MINECART, EntityType.COMMAND_BLOCK_MINECART, EntityType.ITEM_FRAME, - EntityType.GLOW_ITEM_FRAME, - EntityType.HAPPY_GHAST - ); + EntityType.GLOW_ITEM_FRAME + )); + if (VersionHelper.isOrAbove1_21_6()) { + try { + Field happyGhastField = EntityType.class.getField("HAPPY_GHAST"); + EntityType happyGhast = (EntityType) happyGhastField.get(null); + set.add(happyGhast); + } catch (NoSuchFieldException | IllegalAccessException ignored) {} + } + return Collections.unmodifiableSet(set); + } private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { var previous = INTERACTIONS.put(key, function); @@ -325,9 +345,10 @@ public class InteractUtils { public static boolean isEntityInteractable(Player player, Entity entity, Item item) { boolean isSneaking = player.isSneaking(); - if (entity.getType() == EntityType.PIGLIN && - item != null && - item.vanillaId().equals(Key.of("minecraft:gold_ingot"))) { + if (EntityUtils.isPiglinWithGoldIngot(entity, item)) { + return true; + } + if (EntityUtils.isHappyGhastRideable(entity) && !isSneaking) { return true; } return switch (entity) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java index 1f35e3e90..62ab60190 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java @@ -3,6 +3,11 @@ 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; @@ -12,6 +17,7 @@ public class ItemTags { public static final Key AXES = Key.of("minecraft:axes"); public static final Key SWORDS = Key.of("minecraft:swords"); + public static final Tag ITEMS_HARNESSES = getHarnessTag(); private ItemTags() {} @@ -23,4 +29,13 @@ public class ItemTags { } return value; } + + public static Tag getHarnessTag() { + if (!VersionHelper.isOrAbove1_21_6()) return null; + try { + return Bukkit.getTag("items", NamespacedKey.minecraft("harnesses"), Material.class); + } catch (Exception e) { + return null; + } + } } From f7b1eb751f36029c9cc4f8684a0d4ddfa2ef2539 Mon Sep 17 00:00:00 2001 From: halogly Date: Fri, 18 Jul 2025 14:07:15 +0800 Subject: [PATCH 03/83] Fix interactable logic and update entity registration Corrects the logic for interactable checks in ItemEventListener to ensure proper event triggering. Removes sneaking check from chiseled bookshelf interaction and updates HAPPY_GHAST entity registration to use valueOf instead of reflection for compatibility with newer versions. --- .../bukkit/item/listener/ItemEventListener.java | 2 +- .../momirealms/craftengine/bukkit/util/InteractUtils.java | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) 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 8f2095acf..b0814f7d9 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 @@ -279,7 +279,7 @@ public class ItemEventListener implements Listener { .withParameter(DirectContextParameters.EVENT, dummy) ); CustomItem customItem = optionalCustomItem.get(); - if (!InteractUtils.isInteractable(player, blockData, hitResult, itemInHand) && !player.isSneaking()) { + if (!(InteractUtils.isInteractable(player, blockData, hitResult, itemInHand) && !player.isSneaking())) { customItem.execute(context, EventTrigger.RIGHT_CLICK); } if (dummy.isCancelled()) { 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 54e1aba40..87014ccae 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 @@ -94,7 +94,6 @@ public class InteractUtils { }); registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> { Direction direction = result.getDirection(); - if (player.isSneaking()) return false; if (blockState instanceof ChiseledBookshelf chiseledBookshelf) { Direction facing = DirectionUtils.toDirection(chiseledBookshelf.getFacing()); return facing == direction; @@ -311,11 +310,7 @@ public class InteractUtils { EntityType.GLOW_ITEM_FRAME )); if (VersionHelper.isOrAbove1_21_6()) { - try { - Field happyGhastField = EntityType.class.getField("HAPPY_GHAST"); - EntityType happyGhast = (EntityType) happyGhastField.get(null); - set.add(happyGhast); - } catch (NoSuchFieldException | IllegalAccessException ignored) {} + set.add(EntityType.valueOf("HAPPY_GHAST")); } return Collections.unmodifiableSet(set); } From 870bd8171c5017cd661eca67a45934194ff2249d Mon Sep 17 00:00:00 2001 From: halogly Date: Fri, 18 Jul 2025 14:37:39 +0800 Subject: [PATCH 04/83] Remove unused imports in ItemEventListener and InteractUtils Cleaned up unused imports from ItemEventListener.java and InteractUtils.java to improve code readability and maintainability. --- .../craftengine/bukkit/item/listener/ItemEventListener.java | 2 -- .../net/momirealms/craftengine/bukkit/util/InteractUtils.java | 1 - 2 files changed, 3 deletions(-) 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 b0814f7d9..3b58cafd7 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 @@ -34,8 +34,6 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.ChiseledBookshelf; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; import org.bukkit.entity.Entity; 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 87014ccae..a3e3c6292 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 @@ -23,7 +23,6 @@ import org.bukkit.entity.minecart.RideableMinecart; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Field; import java.util.*; public class InteractUtils { From 76e98cda009e718f86794834fd58fc4c5feec353 Mon Sep 17 00:00:00 2001 From: halogly Date: Fri, 18 Jul 2025 14:38:46 +0800 Subject: [PATCH 05/83] Update ItemEventListener.java --- .../craftengine/bukkit/item/listener/ItemEventListener.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 3b58cafd7..9cd48510d 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 @@ -53,7 +53,10 @@ import org.bukkit.inventory.EnchantingInventory; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; public class ItemEventListener implements Listener { private final BukkitCraftEngine plugin; From 774a9a920774a5a16ee0d519ece2e73c43130f52 Mon Sep 17 00:00:00 2001 From: halogly Date: Fri, 18 Jul 2025 14:42:44 +0800 Subject: [PATCH 06/83] Refactor entity interaction and imports Replaced redundant event.getPlayer() call with local variable in ItemEventListener and updated import statements in EntityUtils for clarity and specificity. --- .../craftengine/bukkit/item/listener/ItemEventListener.java | 2 +- .../net/momirealms/craftengine/bukkit/util/EntityUtils.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) 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 9cd48510d..0eaa67cb5 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 @@ -69,7 +69,7 @@ public class ItemEventListener implements Listener { public void onInteractEntity(PlayerInteractEntityEvent event) { Player player = event.getPlayer(); Entity entity = event.getRightClicked(); - BukkitServerPlayer serverPlayer = this.plugin.adapt(event.getPlayer()); + BukkitServerPlayer serverPlayer = this.plugin.adapt(player); if (serverPlayer == null) return; InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; Item itemInHand = serverPlayer.getItemInHand(hand); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index 0dfe4ec0d..070dd8ebe 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -8,7 +8,10 @@ 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.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.EquipmentSlot; From 8a970fa2f3fa683f86abe273f769c4ac70262366 Mon Sep 17 00:00:00 2001 From: halogly Date: Fri, 18 Jul 2025 14:47:32 +0800 Subject: [PATCH 07/83] Update ItemEventListener.java --- .../item/listener/ItemEventListener.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) 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 0eaa67cb5..dc650c884 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 @@ -77,18 +77,17 @@ public class ItemEventListener implements Listener { if (ItemUtils.isEmpty(itemInHand)) return; Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isEmpty()) return; + if (InteractUtils.isEntityInteractable(player, entity, itemInHand)) return; - if (!InteractUtils.isEntityInteractable(player, entity, itemInHand)) { - Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) - .withParameter(DirectContextParameters.HAND, hand) - ); - CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.RIGHT_CLICK); - } + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) + .withParameter(DirectContextParameters.HAND, hand) + ); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.RIGHT_CLICK); } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) From 4d9d8169e8226e666159e2f955b68d3078e3d7ca Mon Sep 17 00:00:00 2001 From: halogly Date: Fri, 18 Jul 2025 16:25:37 +0800 Subject: [PATCH 08/83] =?UTF-8?q?=E5=88=86=E5=BC=80=E6=BD=9C=E8=A1=8C?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/InteractUtils.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) 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 a3e3c6292..99b3398a2 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 @@ -338,20 +338,22 @@ public class InteractUtils { } public static boolean isEntityInteractable(Player player, Entity entity, Item item) { - boolean isSneaking = player.isSneaking(); if (EntityUtils.isPiglinWithGoldIngot(entity, item)) { return true; } - if (EntityUtils.isHappyGhastRideable(entity) && !isSneaking) { - return true; + if (!player.isSneaking()) { + if (EntityUtils.isHappyGhastRideable(entity)) { + return true; + } + return switch (entity) { + case Boat ignored -> true; + case RideableMinecart ignored -> true; + case Steerable steerable -> steerable.hasSaddle(); + default -> INTERACTABLE_ENTITIES.contains(entity.getType()); + }; } - return switch (entity) { - case ChestBoat ignored -> true; - case Boat ignored -> !isSneaking; - case RideableMinecart ignored -> !isSneaking; - case Steerable steerable -> !isSneaking && steerable.hasSaddle(); - default -> INTERACTABLE_ENTITIES.contains(entity.getType()); - }; + return entity instanceof ChestBoat + || INTERACTABLE_ENTITIES.contains(entity.getType()); } public static boolean willConsume(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { From f5d9bd8c1a1d0794a8ec8d7332ebb759470297e4 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 18 Jul 2025 19:12:05 +0800 Subject: [PATCH 09/83] =?UTF-8?q?refactor(network):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E7=BD=91=E7=BB=9C=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 10 +-- .../network/payload/NetWorkDataTypes.java | 66 +++++-------------- 2 files changed, 20 insertions(+), 56 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 21685624a..8233043b3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1891,9 +1891,9 @@ public class PacketConsumers { if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; FriendlyByteBuf buf = discardedPayload.toBuffer(); - NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); + NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class); if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { - int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); + int clientBlockRegistrySize = dataType.decode(buf); int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); if (clientBlockRegistrySize != serverBlockRegistrySize) { user.kick(Component.translatable( @@ -1906,10 +1906,10 @@ public class PacketConsumers { user.setClientModState(true); } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { if (!VersionHelper.isOrAbove1_20_2()) return; - if (dataType.as(Boolean.class).decode(buf)) { + if (dataType.decode(buf)) { FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); - dataType.writeType(bufPayload); - dataType.as(Boolean.class).encode(bufPayload, true); + bufPayload.writeEnumConstant(dataType); + dataType.encode(bufPayload, true); user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java index 5655e1028..37da1618d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java @@ -1,64 +1,28 @@ package net.momirealms.craftengine.bukkit.plugin.network.payload; +import io.netty.buffer.ByteBuf; -import net.momirealms.craftengine.core.util.FriendlyByteBuf; +public enum NetWorkDataTypes { + CLIENT_CUSTOM_BLOCK(NetWorkCodecs.INTEGER), + CANCEL_BLOCK_UPDATE(NetWorkCodecs.BOOLEAN); -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Function; + private final NetWorkCodec codec; -public class NetWorkDataTypes { - private static final Map> id2NetWorkDataTypes = new HashMap<>(); - - public static final NetWorkDataTypes CLIENT_CUSTOM_BLOCK = - new NetWorkDataTypes<>(0, FriendlyByteBuf::readInt, FriendlyByteBuf::writeInt); - - public static final NetWorkDataTypes CANCEL_BLOCK_UPDATE = - new NetWorkDataTypes<>(1, FriendlyByteBuf::readBoolean, FriendlyByteBuf::writeBoolean); - - static { - register(CLIENT_CUSTOM_BLOCK); - register(CANCEL_BLOCK_UPDATE); + NetWorkDataTypes(NetWorkCodec codec) { + this.codec = codec; } - private static void register(NetWorkDataTypes type) { - id2NetWorkDataTypes.put(type.id, type); + public NetWorkCodec codec() { + return codec; } - private final int id; - private final Function decoder; - private final BiConsumer encoder; - - public NetWorkDataTypes(int id, Function decoder, BiConsumer encoder) { - this.id = id; - this.decoder = decoder; - this.encoder = encoder; + @SuppressWarnings("unchecked") + public V decode(ByteBuf buf) { + return (V) codec.decode(buf); } - public T decode(FriendlyByteBuf buf) { - return decoder.apply(buf); - } - - public void encode(FriendlyByteBuf buf, T data) { - encoder.accept(buf, data); - } - - public int id() { - return id; - } - - public void writeType(FriendlyByteBuf buf) { - buf.writeVarInt(id); - } - - public static NetWorkDataTypes readType(FriendlyByteBuf buf) { - int id = buf.readVarInt(); - return id2NetWorkDataTypes.get(id); - } - - @SuppressWarnings({"unchecked", "unused"}) - public NetWorkDataTypes as(Class clazz) { - return (NetWorkDataTypes) this; + @SuppressWarnings("unchecked") + public void encode(ByteBuf buf, V value) { + ((NetWorkCodec) codec).encode(buf, value); } } \ No newline at end of file From 453c1f5c1f5c79db2bbacec58350dd99fbb8dcae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sat, 19 Jul 2025 00:28:55 +0800 Subject: [PATCH 10/83] feat: split lore components --- .../factory/ComponentItemFactory1_21_5.java | 6 +---- .../craftengine/core/item/ItemFactory.java | 3 +-- .../core/util/AdventureHelper.java | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java index af0981b60..af576f13d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java @@ -90,11 +90,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (lore == null || lore.isEmpty()) { item.resetComponent(ComponentTypes.LORE); } else { - List loreTags = new ArrayList<>(); - for (Component component : lore) { - loreTags.add(AdventureHelper.componentToTag(component)); - } - item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); + item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(lore.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToTag).toList())); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index d403ba310..996db1af9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -16,7 +16,6 @@ import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; public abstract class ItemFactory, I> { protected final CraftEngine plugin; @@ -112,7 +111,7 @@ public abstract class ItemFactory, I> { protected void loreComponent(W item, List component) { if (component != null && !component.isEmpty()) { - loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList())); + loreJson(item, component.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToJson).toList()); } else { loreJson(item, null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 3ed1f6048..92d81f1da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -1,11 +1,17 @@ package net.momirealms.craftengine.core.util; import com.google.gson.JsonElement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentIteratorType; import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -29,6 +35,7 @@ public class AdventureHelper { private final MiniMessage miniMessageCustom; private final GsonComponentSerializer gsonComponentSerializer; private final NBTComponentSerializer nbtComponentSerializer; + private static final TextReplacementConfig REPLACE_LF = TextReplacementConfig.builder().matchLiteral("\n").replacement(Component.newline()).build(); private AdventureHelper() { this.miniMessage = MiniMessage.builder().build(); @@ -209,6 +216,24 @@ public class AdventureHelper { return getNBT().deserialize(tag); } + public static List split(Component component) { + List result = new ArrayList<>(1); + Component line = Component.empty(); + for (Iterator it = component.replaceText(REPLACE_LF).iterator(ComponentIteratorType.DEPTH_FIRST); it.hasNext(); ) { + Component child = it.next().children(Collections.emptyList()); + if (Component.EQUALS.test(child, Component.newline())) { + result.add(line); + line = Component.empty(); + } else { + line = line.append(child); + } + } + if (Component.IS_NOT_EMPTY.test(line)) { + result.add(line); + } + return result; + } + /** * Checks if a character is a legacy color code. * From 0c6624819c476440e57d5a30429e65cee9bcbe80 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 10:59:33 +0800 Subject: [PATCH 11/83] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=90=AF=E7=94=A8=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=A8=A1=E7=BB=84?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/PacketConsumers.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 21685624a..49caecbe3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -105,7 +105,7 @@ public class PacketConsumers { byte yHeadRot = buf.readByte(); int data = buf.readVarInt(); // Falling blocks - int remapped = remap(data); + int remapped = user.clientModEnabled() ? remapMOD(data) : remap(data); if (remapped != data) { int xa = buf.readShort(); int ya = buf.readShort(); @@ -428,7 +428,7 @@ public class PacketConsumers { if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) { return; } - int state = remap(before); + int state = user.clientModEnabled() ? remapMOD(before) : remap(before); if (state == before) { return; } @@ -450,7 +450,7 @@ public class PacketConsumers { BlockPos blockPos = buf.readBlockPos(); int state = buf.readInt(); boolean global = buf.readBoolean(); - int newState = remap(state); + int newState = user.clientModEnabled() ? remapMOD(state) : remap(state); if (newState == state) { return; } @@ -1006,7 +1006,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); @@ -1046,7 +1046,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); @@ -1086,7 +1086,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); From 17b531c56ca3b26bd22ce8823a25c91360ad7ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sat, 19 Jul 2025 22:32:37 +0800 Subject: [PATCH 12/83] feat: better split lore impl --- .../factory/ComponentItemFactory1_21_5.java | 6 ++- .../core/item/AbstractItemManager.java | 23 +++++++--- .../craftengine/core/item/ItemFactory.java | 3 +- .../item/modifier/DynamicLoreModifier.java | 13 +++--- .../core/item/modifier/LoreModification.java | 45 +++++++++++++++++++ .../core/item/modifier/LoreModifier.java | 28 ++++-------- .../core/util/AdventureHelper.java | 2 +- .../core/util/ResourceConfigUtils.java | 11 +++++ 8 files changed, 97 insertions(+), 34 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java index af576f13d..af0981b60 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java @@ -90,7 +90,11 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (lore == null || lore.isEmpty()) { item.resetComponent(ComponentTypes.LORE); } else { - item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(lore.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToTag).toList())); + List loreTags = new ArrayList<>(); + for (Component component : lore) { + loreTags.add(AdventureHelper.componentToTag(component)); + } + item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 6b75dc648..5aebb5f74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -534,15 +534,26 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return new CustomNameModifier<>(name); }, "custom-name", "item-name", "display-name"); } + Function> loreModificationListParser = (obj) -> { + if (obj instanceof List list) { + List modifications = new ArrayList<>(list.size()); + for (Object entry : list) { + if (entry instanceof Map map) { + modifications.add(new LoreModification(ResourceConfigUtils.getAsEnumOrDefault(map.get("action").toString().toUpperCase(Locale.ROOT), LoreModification.Action.class, LoreModification.Action.SET), ResourceConfigUtils.getAsInt(map.get("priority"), "priority"), ResourceConfigUtils.getAsBoolean(map.get("split-lines"), "split-lines"), MiscUtils.getAsStringList(map.get("content")))); + } else { + modifications.add(new LoreModification(List.of(entry.toString()))); + } + } + return modifications; + } + return Collections.emptyList(); + }; + registerDataType((obj) -> new LoreModifier<>(loreModificationListParser.apply(obj)), "lore", "display-lore", "description"); registerDataType((obj) -> { - List lore = MiscUtils.getAsStringList(obj); - return new LoreModifier<>(lore); - }, "lore", "display-lore", "description"); - registerDataType((obj) -> { - Map> dynamicLore = new LinkedHashMap<>(); + Map> dynamicLore = new LinkedHashMap<>(); if (obj instanceof Map map) { for (Map.Entry entry : map.entrySet()) { - dynamicLore.put(entry.getKey().toString(), MiscUtils.getAsStringList(entry.getValue())); + dynamicLore.put(entry.getKey().toString(), loreModificationListParser.apply(entry.getValue())); } } return new DynamicLoreModifier<>(dynamicLore); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index 996db1af9..bed14fa59 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; +import java.util.stream.Collectors; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; @@ -111,7 +112,7 @@ public abstract class ItemFactory, I> { protected void loreComponent(W item, List component) { if (component != null && !component.isEmpty()) { - loreJson(item, component.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToJson).toList()); + loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList())); } else { loreJson(item, null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java index 65392a1b8..fd7bd99d3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java @@ -1,10 +1,11 @@ package net.momirealms.craftengine.core.item.modifier; +import java.util.stream.Stream; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -16,15 +17,15 @@ import java.util.Optional; public class DynamicLoreModifier implements ItemDataModifier { public static final String CONTEXT_TAG_KEY = "craftengine:display_context"; - private final Map> displayContexts; + private final Map> displayContexts; private final String defaultContext; - public DynamicLoreModifier(Map> displayContexts) { + public DynamicLoreModifier(Map> displayContexts) { this.defaultContext = displayContexts.keySet().iterator().next(); this.displayContexts = displayContexts; } - public Map> displayContexts() { + public Map> displayContexts() { return Collections.unmodifiableMap(this.displayContexts); } @@ -36,11 +37,11 @@ public class DynamicLoreModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultContext).toString(); - List lore = this.displayContexts.get(displayContext); + List lore = this.displayContexts.get(displayContext); if (lore == null) { lore = this.displayContexts.get(this.defaultContext); } - item.loreComponent(lore.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); + item.loreComponent(lore.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); return item; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java new file mode 100644 index 000000000..45ecd76ae --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java @@ -0,0 +1,45 @@ +package net.momirealms.craftengine.core.item.modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.util.AdventureHelper; +public record LoreModification(Action action, int priority, boolean split, List content) implements Comparable { + public LoreModification(List content) { + this(Action.SET, 0, false, content); + } + public LoreModification(Action action, int priority, boolean split, List content) { + this.action = action; + this.priority = priority; + this.split = split; + if (Config.addNonItalicTag()) { + List processed = new ArrayList<>(content.size()); + for (String arg : content) { + processed.add(arg.startsWith("") ? arg : "" + arg); + } + this.content = processed; + } else { + this.content = content; + } + } + public Stream apply(Stream lore, ItemBuildContext context) { + return switch (action) { + case PREPEND -> Stream.concat(parseContent(context), lore); + case APPEND -> Stream.concat(lore, parseContent(context)); + default -> parseContent(context); + }; + } + private Stream parseContent(ItemBuildContext context) { + Stream parsed = content.stream().map(string -> AdventureHelper.miniMessage().deserialize(string, context.tagResolvers())); + return split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed; + } + @Override + public int compareTo(LoreModification other) { + return Integer.compare(priority, other.priority); + } + public enum Action { + SET, PREPEND, APPEND + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java index 6c5c88a59..f76c1bb60 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java @@ -1,35 +1,25 @@ package net.momirealms.craftengine.core.item.modifier; +import java.util.ArrayList; +import java.util.stream.Stream; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; -import java.util.ArrayList; import java.util.List; public class LoreModifier implements ItemDataModifier { - private final List argument; + private final List argument; - public LoreModifier(List argument) { - if (Config.addNonItalicTag()) { - List processed = new ArrayList<>(argument.size()); - for (String arg : argument) { - if (arg.startsWith("")) { - processed.add(arg); - } else { - processed.add("" + arg); - } - } - this.argument = processed; - } else { - this.argument = argument; - } + public LoreModifier(List argument) { + argument = new ArrayList<>(argument); + argument.sort(null); + this.argument = List.copyOf(argument); } @Override @@ -39,7 +29,7 @@ public class LoreModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { - item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); + item.loreComponent(argument.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); return item; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 92d81f1da..f58769a92 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -216,7 +216,7 @@ public class AdventureHelper { return getNBT().deserialize(tag); } - public static List split(Component component) { + public static List splitLines(Component component) { List result = new ArrayList<>(1); Component line = Component.empty(); for (Iterator it = component.replaceText(REPLACE_LF).iterator(ComponentIteratorType.DEPTH_FIRST); it.hasNext(); ) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index b6a40aa27..a9671f7de 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -20,6 +20,17 @@ public final class ResourceConfigUtils { return raw != null ? function.apply(raw) : defaultValue; } + public static > E getAsEnumOrDefault(Object o, Class clazz, E defaultValue) { + if (o == null) { + return defaultValue; + } + try { + return Enum.valueOf(clazz, o.toString()); + } catch (IllegalArgumentException e) { + return defaultValue; + } + } + public static T requireNonNullOrThrow(T obj, String node) { if (obj == null) throw new LocalizedResourceConfigException(node); From f68432b761487eb9ae923d2286d8eec130a18a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sat, 19 Jul 2025 22:44:12 +0800 Subject: [PATCH 13/83] refractor: import --- .../java/net/momirealms/craftengine/core/item/ItemFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index bed14fa59..d403ba310 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; -import java.util.stream.Collectors; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; @@ -17,6 +16,7 @@ import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; public abstract class ItemFactory, I> { protected final CraftEngine plugin; From af7241aade85ed56c627e96c8fef82a9687e11e8 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 22:54:48 +0800 Subject: [PATCH 14/83] =?UTF-8?q?fix(network):=20=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D1.20.2~1.20.4=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E6=A8=A1=E7=BB=84=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 41 +------------------ .../plugin/network/PacketConsumers.java | 3 +- 2 files changed, 3 insertions(+), 41 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index a8d5c862d..161171c20 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,23 +1,12 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.entity.data.HappyGhastData; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.incendo.cloud.Command; -import org.incendo.cloud.bukkit.parser.location.LocationParser; -import org.incendo.cloud.parser.standard.IntegerParser; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; public class TestCommand extends BukkitCommandFeature { @@ -29,35 +18,9 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) - .required("location", LocationParser.locationParser()) - .required("remove", IntegerParser.integerParser()) .handler(context -> { Player player = context.sender(); - int removeEntityId = context.get("remove"); - if (removeEntityId >= 0) { - try { - Object packet = NetworkReflections.constructor$ClientboundRemoveEntitiesPacket.newInstance((Object) new int[]{removeEntityId}); - plugin().adapt(player).sendPacket(packet, true); - player.sendMessage("发送成功"); - } catch (ReflectiveOperationException e) { - player.sendMessage("发送失败"); - } - return; - } - Location location = context.get("location"); - int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); - List packets = new ArrayList<>(); - List cachedShulkerValues = new ArrayList<>(); - HappyGhastData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, cachedShulkerValues); // NO AI - // HappyGhastData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, cachedShulkerValues); // Invisible - HappyGhastData.StaysStill.addEntityDataIfNotDefaultValue(true, cachedShulkerValues); - packets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - entityId, UUID.randomUUID(), location.x(), location.y(), location.z(), 0, location.getYaw(), - MEntityTypes.HAPPY_GHAST, 0, CoreReflections.instance$Vec3$Zero, 0 - )); - packets.add(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, List.copyOf(cachedShulkerValues))); - plugin().adapt(player).sendPackets(packets, true); - player.sendMessage("发送成功 id: " + entityId); + player.sendMessage("客户端模组状态: " + BukkitNetworkManager.instance().getUser(player).clientModEnabled()); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 49caecbe3..72a2571c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1884,7 +1884,7 @@ public class PacketConsumers { public static final TriConsumer CUSTOM_PAYLOAD = (user, event, packet) -> { try { - if (!VersionHelper.isOrAbove1_20_5()) return; + if (!VersionHelper.isOrAbove1_20_2()) return; Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { Payload discardedPayload = DiscardedPayload.from(payload); @@ -1905,7 +1905,6 @@ public class PacketConsumers { } user.setClientModState(true); } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { - if (!VersionHelper.isOrAbove1_20_2()) return; if (dataType.as(Boolean.class).decode(buf)) { FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); dataType.writeType(bufPayload); From 407d0137252fbedc76c80c9315e8ee188810f413 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 23:21:19 +0800 Subject: [PATCH 15/83] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D1.20.2~?= =?UTF-8?q?1.20.4=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=A8=A1=E7=BB=84=E6=A3=80?= =?UTF-8?q?=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 53 +++++++++++-------- .../network/payload/UnknownPayload.java | 28 ++++++++++ .../minecraft/NetworkReflections.java | 18 +++++++ 3 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 72a2571c7..661920946 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -29,6 +29,7 @@ import net.momirealms.craftengine.bukkit.plugin.network.handler.*; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; import net.momirealms.craftengine.bukkit.plugin.network.payload.NetWorkDataTypes; import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; +import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; @@ -1886,31 +1887,37 @@ public class PacketConsumers { try { if (!VersionHelper.isOrAbove1_20_2()) return; Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); + System.out.println(payload.getClass()); + Payload clientPayload; if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { - Payload discardedPayload = DiscardedPayload.from(payload); - if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) + clientPayload = DiscardedPayload.from(payload); + } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$UnknownPayload.isInstance(payload)) { + clientPayload = UnknownPayload.from(payload); + } else { + return; + } + if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) + return; + FriendlyByteBuf buf = clientPayload.toBuffer(); + NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); + if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { + int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); + int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); + if (clientBlockRegistrySize != serverBlockRegistrySize) { + user.kick(Component.translatable( + "disconnect.craftengine.block_registry_mismatch", + TranslationArgument.numeric(clientBlockRegistrySize), + TranslationArgument.numeric(serverBlockRegistrySize) + )); return; - FriendlyByteBuf buf = discardedPayload.toBuffer(); - NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); - if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { - int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); - int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); - if (clientBlockRegistrySize != serverBlockRegistrySize) { - user.kick(Component.translatable( - "disconnect.craftengine.block_registry_mismatch", - TranslationArgument.numeric(clientBlockRegistrySize), - TranslationArgument.numeric(serverBlockRegistrySize) - )); - return; - } - user.setClientModState(true); - } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { - if (dataType.as(Boolean.class).decode(buf)) { - FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); - dataType.writeType(bufPayload); - dataType.as(Boolean.class).encode(bufPayload, true); - user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); - } + } + user.setClientModState(true); + } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { + if (dataType.as(Boolean.class).decode(buf)) { + FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); + dataType.writeType(bufPayload); + dataType.as(Boolean.class).encode(bufPayload, true); + user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); } } } catch (Throwable e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java new file mode 100644 index 000000000..4143eea27 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java @@ -0,0 +1,28 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +public record UnknownPayload(Key channel, ByteBuf rawPayload) implements Payload{ + + public static UnknownPayload from(Object payload) { + try { + Object id = NetworkReflections.field$UnknownPayload$id.get(payload); + ByteBuf data = (ByteBuf) NetworkReflections.field$UnknownPayload$data.get(payload); + Key channel = KeyUtils.resourceLocationToKey(id); + return new UnknownPayload(channel, data); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to create UnknownPayload", e); + return null; + } + } + + @Override + public FriendlyByteBuf toBuffer() { + return new FriendlyByteBuf(rawPayload); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index 6c1d427a9..08254bcba 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1621,4 +1621,22 @@ public final class NetworkReflections { throw new ReflectionInitException("Failed to initialize HashedStack$STREAM_CODEC", e); } } + + // 1.20.2~1.20.4 + public static final Class clazz$UnknownPayload = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundCustomPayloadPacket$UnknownPayload") + ), + VersionHelper.isOrAbove1_20_2() && !VersionHelper.isOrAbove1_20_5() + ); + + // 1.20.2~1.20.4 + public static final Field field$UnknownPayload$id = Optional.ofNullable(clazz$UnknownPayload) + .map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$ResourceLocation, 0)) + .orElse(null); + + // 1.20.2~1.20.4 + public static final Field field$UnknownPayload$data = Optional.ofNullable(clazz$UnknownPayload) + .map(it -> ReflectionUtils.getDeclaredField(it, ByteBuf.class, 0)) + .orElse(null); } From ad6bd3ae3caa185bcd8c4593a8bb6c764539cd07 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 23:32:36 +0800 Subject: [PATCH 16/83] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D1.20.2~?= =?UTF-8?q?1.20.4=E5=8F=91=E8=87=AA=E5=AE=9A=E4=B9=89=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/PacketConsumers.java | 1 - .../plugin/reflection/minecraft/NetworkReflections.java | 9 ++++++++- .../bukkit/plugin/user/BukkitServerPlayer.java | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 661920946..dcb6b3a7d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1887,7 +1887,6 @@ public class PacketConsumers { try { if (!VersionHelper.isOrAbove1_20_2()) return; Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); - System.out.println(payload.getClass()); Payload clientPayload; if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { clientPayload = DiscardedPayload.from(payload); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index 08254bcba..b5bd1bd0f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1248,7 +1248,9 @@ public final class NetworkReflections { ); public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( - ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) + VersionHelper.isOrAbove1_20_2() + ? ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, clazz$CustomPacketPayload) + : ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) ); // 1.20.2+ @@ -1639,4 +1641,9 @@ public final class NetworkReflections { public static final Field field$UnknownPayload$data = Optional.ofNullable(clazz$UnknownPayload) .map(it -> ReflectionUtils.getDeclaredField(it, ByteBuf.class, 0)) .orElse(null); + + // 1.20.2~1.20.4 + public static final Constructor constructor$UnknownPayload = Optional.ofNullable(clazz$UnknownPayload) + .map(ReflectionUtils::getTheOnlyConstructor) + .orElse(null); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 74430caf7..6bcf22b32 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -307,7 +307,9 @@ public class BukkitServerPlayer extends Player { try { Object channelKey = KeyUtils.toResourceLocation(channel); Object dataPayload; - if (DiscardedPayload.useNewMethod) { + if (NetworkReflections.clazz$UnknownPayload != null) { + dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } else if (DiscardedPayload.useNewMethod) { dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); } else { dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); From 64466257bab1eac0375c666a32d8e283c637e513 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 23:34:23 +0800 Subject: [PATCH 17/83] =?UTF-8?q?fix(network):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/user/BukkitServerPlayer.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 6bcf22b32..db820d674 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -304,6 +304,9 @@ public class BukkitServerPlayer extends Player { @Override public void sendCustomPayload(Key channel, byte[] data) { + if (!VersionHelper.isOrAbove1_20_2()) { + throw new UnsupportedOperationException("Cannot send custom payload to " + name() + " because the server is running a version below 1.20.2"); + } try { Object channelKey = KeyUtils.toResourceLocation(channel); Object dataPayload; From 70925ee2c98af2acab9acf29ccc51f003bafb8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sun, 20 Jul 2025 00:07:32 +0800 Subject: [PATCH 18/83] fix: style loss --- .../core/util/AdventureHelper.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index f58769a92..f3af38fc8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -36,6 +36,20 @@ public class AdventureHelper { private final GsonComponentSerializer gsonComponentSerializer; private final NBTComponentSerializer nbtComponentSerializer; private static final TextReplacementConfig REPLACE_LF = TextReplacementConfig.builder().matchLiteral("\n").replacement(Component.newline()).build(); + /** + * This iterator slices a component into individual parts that + *
    + *
  • Can be used individually without style loss
  • + *
  • Can be concatenated to form the original component, given that children are dropped
  • + *
+ * Any {@link net.kyori.adventure.text.ComponentIteratorFlag}s are ignored. + */ + private static final ComponentIteratorType SLICER = (component, deque, flags) -> { + final List children = component.children(); + for (int i = children.size() - 1; i >= 0; i--) { + deque.addFirst(children.get(i).applyFallbackStyle(component.style())); + } + }; private AdventureHelper() { this.miniMessage = MiniMessage.builder().build(); @@ -219,17 +233,17 @@ public class AdventureHelper { public static List splitLines(Component component) { List result = new ArrayList<>(1); Component line = Component.empty(); - for (Iterator it = component.replaceText(REPLACE_LF).iterator(ComponentIteratorType.DEPTH_FIRST); it.hasNext(); ) { + for (Iterator it = component.replaceText(REPLACE_LF).iterator(SLICER); it.hasNext(); ) { Component child = it.next().children(Collections.emptyList()); - if (Component.EQUALS.test(child, Component.newline())) { - result.add(line); + if (child instanceof TextComponent text && text.content().equals(Component.newline().content())) { + result.add(line.compact()); line = Component.empty(); } else { line = line.append(child); } } if (Component.IS_NOT_EMPTY.test(line)) { - result.add(line); + result.add(line.compact()); } return result; } From 5abdb8af1d870cca2fbb6406d511f9f8344b3de7 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 20 Jul 2025 00:32:30 +0800 Subject: [PATCH 19/83] =?UTF-8?q?feat(network):=20=E5=AE=8C=E5=96=84sendCu?= =?UTF-8?q?stomPayload=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../minecraft/NetworkReflections.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index b5bd1bd0f..6c11c869e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1250,7 +1250,7 @@ public final class NetworkReflections { public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( VersionHelper.isOrAbove1_20_2() ? ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, clazz$CustomPacketPayload) - : ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) + : ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$FriendlyByteBuf) ); // 1.20.2+ diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index db820d674..5e78643a6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -304,20 +304,22 @@ public class BukkitServerPlayer extends Player { @Override public void sendCustomPayload(Key channel, byte[] data) { - if (!VersionHelper.isOrAbove1_20_2()) { - throw new UnsupportedOperationException("Cannot send custom payload to " + name() + " because the server is running a version below 1.20.2"); - } try { Object channelKey = KeyUtils.toResourceLocation(channel); - Object dataPayload; - if (NetworkReflections.clazz$UnknownPayload != null) { - dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); - } else if (DiscardedPayload.useNewMethod) { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); + Object responsePacket; + if (VersionHelper.isOrAbove1_20_2()) { + Object dataPayload; + if (NetworkReflections.clazz$UnknownPayload != null) { + dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } else if (DiscardedPayload.useNewMethod) { + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); + } else { + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } + responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); } else { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(channelKey, FastNMS.INSTANCE.constructor$FriendlyByteBuf(Unpooled.wrappedBuffer(data))); } - Object responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); this.sendPacket(responsePacket, true); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to send custom payload to " + name(), e); From 107622dea0d719848c5f2246674a63915d10859c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 20 Jul 2025 02:30:11 +0800 Subject: [PATCH 20/83] =?UTF-8?q?=E4=BC=98=E5=8C=96lore=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/block/properties/Properties.java | 2 +- .../core/item/AbstractItemManager.java | 22 +-- .../craftengine/core/item/ItemFactory.java | 3 +- .../core/item/modifier/LoreModification.java | 45 ------ .../core/item/modifier/LoreModifier.java | 55 -------- .../{ => lore}/DynamicLoreModifier.java | 30 ++-- .../item/modifier/lore/LoreModification.java | 39 ++++++ .../modifier/lore/LoreModificationHolder.java | 11 ++ .../core/item/modifier/lore/LoreModifier.java | 128 ++++++++++++++++++ .../core/pack/ResourceLocation.java | 2 +- .../core/util/AdventureHelper.java | 6 +- .../craftengine/core/util/MiscUtils.java | 14 ++ .../core/util/ResourceConfigUtils.java | 9 +- 13 files changed, 217 insertions(+), 149 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java rename core/src/main/java/net/momirealms/craftengine/core/item/modifier/{ => lore}/DynamicLoreModifier.java (63%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java index 5636e7ae9..a54c56afa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.*; import java.util.Map; -public class Properties { +public final class Properties { public static final Key BOOLEAN = Key.of("craftengine:boolean"); public static final Key INT = Key.of("craftengine:int"); public static final Key STRING = Key.of("craftengine:string"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 5aebb5f74..0bb7a59cf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -9,6 +9,8 @@ import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.equipment.*; import net.momirealms.craftengine.core.item.modifier.*; +import net.momirealms.craftengine.core.item.modifier.lore.DynamicLoreModifier; +import net.momirealms.craftengine.core.item.modifier.lore.LoreModifier; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.LoadingSequence; @@ -534,26 +536,12 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return new CustomNameModifier<>(name); }, "custom-name", "item-name", "display-name"); } - Function> loreModificationListParser = (obj) -> { - if (obj instanceof List list) { - List modifications = new ArrayList<>(list.size()); - for (Object entry : list) { - if (entry instanceof Map map) { - modifications.add(new LoreModification(ResourceConfigUtils.getAsEnumOrDefault(map.get("action").toString().toUpperCase(Locale.ROOT), LoreModification.Action.class, LoreModification.Action.SET), ResourceConfigUtils.getAsInt(map.get("priority"), "priority"), ResourceConfigUtils.getAsBoolean(map.get("split-lines"), "split-lines"), MiscUtils.getAsStringList(map.get("content")))); - } else { - modifications.add(new LoreModification(List.of(entry.toString()))); - } - } - return modifications; - } - return Collections.emptyList(); - }; - registerDataType((obj) -> new LoreModifier<>(loreModificationListParser.apply(obj)), "lore", "display-lore", "description"); + registerDataType(LoreModifier::createLoreModifier, "lore", "display-lore", "description"); registerDataType((obj) -> { - Map> dynamicLore = new LinkedHashMap<>(); + Map> dynamicLore = new LinkedHashMap<>(); if (obj instanceof Map map) { for (Map.Entry entry : map.entrySet()) { - dynamicLore.put(entry.getKey().toString(), loreModificationListParser.apply(entry.getValue())); + dynamicLore.put(entry.getKey().toString(), LoreModifier.createLoreModifier(entry.getValue())); } } return new DynamicLoreModifier<>(dynamicLore); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index d403ba310..365582553 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -16,7 +16,6 @@ import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; public abstract class ItemFactory, I> { protected final CraftEngine plugin; @@ -112,7 +111,7 @@ public abstract class ItemFactory, I> { protected void loreComponent(W item, List component) { if (component != null && !component.isEmpty()) { - loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList())); + loreJson(item, component.stream().map(AdventureHelper::componentToJson).toList()); } else { loreJson(item, null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java deleted file mode 100644 index 45ecd76ae..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.momirealms.craftengine.core.item.modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; -import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.util.AdventureHelper; -public record LoreModification(Action action, int priority, boolean split, List content) implements Comparable { - public LoreModification(List content) { - this(Action.SET, 0, false, content); - } - public LoreModification(Action action, int priority, boolean split, List content) { - this.action = action; - this.priority = priority; - this.split = split; - if (Config.addNonItalicTag()) { - List processed = new ArrayList<>(content.size()); - for (String arg : content) { - processed.add(arg.startsWith("") ? arg : "" + arg); - } - this.content = processed; - } else { - this.content = content; - } - } - public Stream apply(Stream lore, ItemBuildContext context) { - return switch (action) { - case PREPEND -> Stream.concat(parseContent(context), lore); - case APPEND -> Stream.concat(lore, parseContent(context)); - default -> parseContent(context); - }; - } - private Stream parseContent(ItemBuildContext context) { - Stream parsed = content.stream().map(string -> AdventureHelper.miniMessage().deserialize(string, context.tagResolvers())); - return split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed; - } - @Override - public int compareTo(LoreModification other) { - return Integer.compare(priority, other.priority); - } - public enum Action { - SET, PREPEND, APPEND - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java deleted file mode 100644 index f76c1bb60..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.momirealms.craftengine.core.item.modifier; - -import java.util.ArrayList; -import java.util.stream.Stream; -import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.item.ComponentKeys; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; - -import java.util.List; - -public class LoreModifier implements ItemDataModifier { - private final List argument; - - public LoreModifier(List argument) { - argument = new ArrayList<>(argument); - argument.sort(null); - this.argument = List.copyOf(argument); - } - - @Override - public String name() { - return "lore"; - } - - @Override - public Item apply(Item item, ItemBuildContext context) { - item.loreComponent(argument.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); - return item; - } - - @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE); - if (previous != null) { - networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("display", "Lore"); - if (previous != null) { - networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } - return item; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java similarity index 63% rename from core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java rename to core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java index fd7bd99d3..5f36228d8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java @@ -1,32 +1,29 @@ -package net.momirealms.craftengine.core.item.modifier; +package net.momirealms.craftengine.core.item.modifier.lore; -import java.util.stream.Stream; -import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; -import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Optional; -public class DynamicLoreModifier implements ItemDataModifier { +public final class DynamicLoreModifier implements ItemDataModifier { public static final String CONTEXT_TAG_KEY = "craftengine:display_context"; - private final Map> displayContexts; - private final String defaultContext; + private final Map> displayContexts; + private final LoreModifier defaultModifier; - public DynamicLoreModifier(Map> displayContexts) { - this.defaultContext = displayContexts.keySet().iterator().next(); + public DynamicLoreModifier(Map> displayContexts) { this.displayContexts = displayContexts; + this.defaultModifier = displayContexts.values().iterator().next(); } - public Map> displayContexts() { - return Collections.unmodifiableMap(this.displayContexts); + public Map> displayContexts() { + return displayContexts; } @Override @@ -36,13 +33,12 @@ public class DynamicLoreModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { - String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultContext).toString(); - List lore = this.displayContexts.get(displayContext); + String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultModifier).toString(); + LoreModifier lore = this.displayContexts.get(displayContext); if (lore == null) { - lore = this.displayContexts.get(this.defaultContext); + lore = this.defaultModifier; } - item.loreComponent(lore.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); - return item; + return lore.apply(item, context); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java new file mode 100644 index 000000000..0b6b8ce34 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.item.modifier.lore; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.TriFunction; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// todo 可以考虑未来添加条件系统 +public record LoreModification(Operation operation, boolean split, String[] content) { + + public Stream apply(Stream lore, ItemBuildContext context) { + return this.operation.function.apply(lore, context, this); + } + + public Stream parseAsStream(ItemBuildContext context) { + Stream parsed = Arrays.stream(this.content).map(string -> AdventureHelper.miniMessage().deserialize(string, context.tagResolvers())); + return this.split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed; + } + + public List parseAsList(ItemBuildContext context) { + return this.parseAsStream(context).collect(Collectors.toList()); + } + + public enum Operation { + APPEND((s, c, modification) -> Stream.concat(s, modification.parseAsStream(c))), + PREPEND((s, c, modification) -> Stream.concat(modification.parseAsStream(c), s)); + + private final TriFunction, ItemBuildContext, LoreModification, Stream> function; + + Operation(TriFunction, ItemBuildContext, LoreModification, Stream> function) { + this.function = function; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java new file mode 100644 index 000000000..7e2c4df28 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.item.modifier.lore; + +import org.jetbrains.annotations.NotNull; + +public record LoreModificationHolder(LoreModification modification, int priority) implements Comparable { + + @Override + public int compareTo(@NotNull LoreModificationHolder o) { + return Integer.compare(priority, o.priority); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java new file mode 100644 index 000000000..61c25a25d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java @@ -0,0 +1,128 @@ +package net.momirealms.craftengine.core.item.modifier.lore; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.*; +import java.util.stream.Stream; + +public sealed interface LoreModifier extends ItemDataModifier + permits LoreModifier.EmptyLoreModifier, LoreModifier.CompositeLoreModifier, LoreModifier.DoubleLoreModifier, LoreModifier.SingleLoreModifier { + + @Override + default String name() { + return "lore"; + } + + @Override + default Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE); + if (previous != null) networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + else networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } else { + Tag previous = item.getTag("display", "Lore"); + if (previous != null) networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + else networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + return item; + } + + static LoreModifier createLoreModifier(Object arg) { + List rawLoreData = MiscUtils.getAsList(arg, Object.class); + List lore = new ArrayList<>(); + label_all_string_check: { + for (Object o : rawLoreData) { + if (o instanceof Map) { + break label_all_string_check; + } else { + lore.add(String.valueOf(o)); + } + } + return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, lore.toArray(new String[0]))); + } + + List modifications = new ArrayList<>(rawLoreData.size() + 1); + int lastPriority = 0; + for (Object o : rawLoreData) { + if (o instanceof Map complexLore) { + String[] content = MiscUtils.getAsStringArray(complexLore.get("content")); + LoreModification.Operation operation = ResourceConfigUtils.getAsEnum(Optional.ofNullable(complexLore.get("operation")).map(String::valueOf).orElse(null), LoreModification.Operation.class, LoreModification.Operation.APPEND); + lastPriority = Optional.ofNullable(complexLore.get("priority")).map(it -> ResourceConfigUtils.getAsInt(it, "priority")).orElse(lastPriority); + boolean split = ResourceConfigUtils.getAsBoolean(complexLore.get("split-lines"), "split-lines"); + modifications.add(new LoreModificationHolder(new LoreModification(operation, split, content), lastPriority)); + } + } + modifications.sort(LoreModificationHolder::compareTo); + return switch (modifications.size()) { + case 0 -> new EmptyLoreModifier<>(); + case 1 -> new SingleLoreModifier<>(modifications.get(0).modification()); + case 2 -> new DoubleLoreModifier<>(modifications.get(0).modification(), modifications.get(1).modification()); + default -> new CompositeLoreModifier<>(modifications.stream().map(LoreModificationHolder::modification).toArray(LoreModification[]::new)); + }; + } + + non-sealed class EmptyLoreModifier implements LoreModifier { + + @Override + public Item apply(Item item, ItemBuildContext context) { + return item; + } + } + + non-sealed class SingleLoreModifier implements LoreModifier { + private final LoreModification modification; + + public SingleLoreModifier(LoreModification modification) { + this.modification = modification; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + item.loreComponent(this.modification.parseAsList(context)); + return item; + } + } + + non-sealed class DoubleLoreModifier implements LoreModifier { + private final LoreModification modification1; + private final LoreModification modification2; + + public DoubleLoreModifier(LoreModification m1, LoreModification m2) { + this.modification1 = m1; + this.modification2 = m2; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + Stream start = Stream.empty(); + this.modification1.apply(start, context); + this.modification2.apply(start, context); + item.loreComponent(start.toList()); + return item; + } + } + + non-sealed class CompositeLoreModifier implements LoreModifier { + private final LoreModification[] modifications; + + public CompositeLoreModifier(LoreModification... modifications) { + this.modifications = modifications; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + item.loreComponent(Arrays.stream(this.modifications).reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); + return item; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java index 4e580df18..1d6c48e33 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java @@ -20,7 +20,7 @@ public final class ResourceLocation { } public static boolean isValidNamespace(String namespace) { - for(int i = 0; i < namespace.length(); ++i) { + for (int i = 0; i < namespace.length(); ++i) { if (!validNamespaceChar(namespace.charAt(i))) { return false; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index f3af38fc8..e988d1f68 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -1,10 +1,6 @@ package net.momirealms.craftengine.core.util; import com.google.gson.JsonElement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; @@ -21,7 +17,7 @@ import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.adventure.NBTComponentSerializer; import net.momirealms.sparrow.nbt.adventure.NBTSerializerOptions; -import java.util.Map; +import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index f3b1bf95c..54195dff8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java @@ -51,6 +51,20 @@ public class MiscUtils { return list; } + public static String[] getAsStringArray(Object o) { + if (o instanceof List list) { + String[] array = new String[list.size()]; + for (int i = 0; i < array.length; i++) { + array[i] = list.get(i).toString(); + } + return array; + } else if (o != null) { + return new String[]{o.toString()}; + } else { + return new String[0]; + } + } + @SuppressWarnings("unchecked") public static List getAsList(Object o, Class clazz) { if (o instanceof List list) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index a9671f7de..dfdaa4317 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -5,10 +5,7 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Function; import java.util.function.Supplier; @@ -20,12 +17,12 @@ public final class ResourceConfigUtils { return raw != null ? function.apply(raw) : defaultValue; } - public static > E getAsEnumOrDefault(Object o, Class clazz, E defaultValue) { + public static > E getAsEnum(Object o, Class clazz, E defaultValue) { if (o == null) { return defaultValue; } try { - return Enum.valueOf(clazz, o.toString()); + return Enum.valueOf(clazz, o.toString().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { return defaultValue; } From 994ea7fc4d18adb7686553fb3b86ef40a8e73b5e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 20 Jul 2025 02:36:09 +0800 Subject: [PATCH 21/83] =?UTF-8?q?=E6=8F=90=E5=8D=87=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/modifier/lore/LoreModifier.java | 9 +++++---- gradle.properties | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java index 61c25a25d..912e4d099 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java @@ -39,16 +39,17 @@ public sealed interface LoreModifier extends ItemDataModifier static LoreModifier createLoreModifier(Object arg) { List rawLoreData = MiscUtils.getAsList(arg, Object.class); - List lore = new ArrayList<>(); + String[] rawLore = new String[rawLoreData.size()]; label_all_string_check: { - for (Object o : rawLoreData) { + for (int i = 0; i < rawLore.length; i++) { + Object o = rawLoreData.get(i); if (o instanceof Map) { break label_all_string_check; } else { - lore.add(String.valueOf(o)); + rawLore[i] = o.toString(); } } - return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, lore.toArray(new String[0]))); + return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, rawLore)); } List modifications = new ArrayList<>(rawLoreData.size() + 1); diff --git a/gradle.properties b/gradle.properties index ef51839f9..1e4e87a6e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,8 +2,8 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.3 -config_version=42 +project_version=0.0.60.4 +config_version=43 lang_version=22 project_group=net.momirealms latest_supported_version=1.21.8 From 2ee574a83db6dce5406fd90fa443918a344e97f2 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 20 Jul 2025 04:45:19 +0800 Subject: [PATCH 22/83] =?UTF-8?q?feat(core):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=20MythicMobs=20=E6=8A=80=E8=83=BD=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 7 +++ .../compatibility/mythicmobs/SkillHelper.java | 29 +++++++++++ .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 1 + .../compatibility/CompatibilityManager.java | 2 + .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 1 + .../function/MythicMobsSkillFunction.java | 48 +++++++++++++++++++ 8 files changed, 90 insertions(+) create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index 656ba4791..56248a777 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -11,6 +11,7 @@ import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterM import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils; import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicMobsListener; +import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.SkillHelper; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners; import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook; @@ -39,6 +40,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager { private final Map levelerProviders; private boolean hasPlaceholderAPI; private boolean hasViaVersion; + private SkillHelper skillExecute; public BukkitCompatibilityManager(BukkitCraftEngine plugin) { this.plugin = plugin; @@ -136,6 +138,11 @@ public class BukkitCompatibilityManager implements CompatibilityManager { } } + @Override + public void skillExecute(String skill, float power, Player player) { + SkillHelper.execute(skill, power, player); + } + @Override public void registerLevelerProvider(String plugin, LevelerProvider provider) { this.levelerProviders.put(plugin, provider); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java new file mode 100644 index 000000000..32162b6d2 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.bukkit.compatibility.mythicmobs; + +import io.lumine.mythic.bukkit.MythicBukkit; +import io.lumine.mythic.core.utils.MythicUtil; +import net.momirealms.craftengine.core.entity.player.Player; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; + +import java.util.ArrayList; +import java.util.List; + +public class SkillHelper { + + public static void execute(String skill, float power, Player player) { + org.bukkit.entity.Player casterPlayer = (org.bukkit.entity.Player) player.platformPlayer(); + Location location = casterPlayer.getLocation(); + LivingEntity target = MythicUtil.getTargetedEntity(casterPlayer); + List targets = new ArrayList<>(); + List locations = null; + if (target != null) { + targets.add(target); + locations = List.of(target.getLocation()); + } + try (MythicBukkit mm = MythicBukkit.inst()) { + mm.getAPIHelper().castSkill(casterPlayer, skill, casterPlayer, location, targets, locations, power); + } + } +} diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 56a24d8f5..375cfd1f0 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -393,6 +393,7 @@ warning.config.function.potion_effect.missing_potion_effect: "Issue foun warning.config.function.set_cooldown.missing_time: "Issue found in file - The config '' is missing the required 'time' argument for 'set_cooldown' function." warning.config.function.set_cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'set_cooldown' function." warning.config.function.remove_cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'remove_cooldown' function." +warning.config.function.mythic_mobs_skill.missing_skill: "Issue found in file - The config '' is missing the required 'skill' argument for 'mythic_mobs_skill' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 11b6758f2..91bfbf70c 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -391,6 +391,7 @@ warning.config.function.potion_effect.missing_potion_effect: "在文件 warning.config.function.set_cooldown.missing_time: "在文件 中发现问题 - 配置项 '' 缺少 'set_cooldown' 函数必需的 'time' 参数" warning.config.function.set_cooldown.missing_id: "在文件 中发现问题 - 配置项 '' 缺少 'set_cooldown' 函数必需的 'id' 参数" warning.config.function.remove_cooldown.missing_id: "在文件 中发现问题 - 配置项 '' 缺少 'remove_cooldown' 函数必需的 'id' 参数" +warning.config.function.mythic_mobs_skill.missing_skill: "在文件 中发现问题 - 配置项 '' 缺少 'mythic_mobs_skill' 函数必需的 'skill' 参数" warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java index 83b15f39b..9459acdfc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java @@ -34,4 +34,6 @@ public interface CompatibilityManager { String parse(Player player1, Player player2, String text); int getPlayerProtocolVersion(UUID uuid); + + void skillExecute(String skill, float power, Player player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 1541a39d2..c61dba386 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -38,6 +38,7 @@ public class EventFunctions { register(CommonFunctions.LEVELER_EXP, new LevelerExpFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.SET_COOLDOWN, new SetCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.REMOVE_COOLDOWN, new RemoveCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.MYTHIC_MOBS_SKILL, new MythicMobsSkillFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 8c0bc6435..055e3260a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -27,4 +27,5 @@ public final class CommonFunctions { public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); public static final Key SWING_HAND = Key.of("craftengine:swing_hand"); public static final Key LEVELER_EXP = Key.of("craftengine:leveler_exp"); + public static final Key MYTHIC_MOBS_SKILL = Key.of("craftengine:mythic_mobs_skill"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java new file mode 100644 index 000000000..bb4a61c85 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; + +public class MythicMobsSkillFunction extends AbstractConditionalFunction { + private final String skill; + private final float power; + + public MythicMobsSkillFunction(String skill, float power, List> predicates) { + super(predicates); + this.skill = skill; + this.power = power; + } + + @Override + protected void runInternal(CTX ctx) { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { + CraftEngine.instance().compatibilityManager().skillExecute(this.skill, this.power, it); + }); + } + + @Override + public Key type() { + return CommonFunctions.MYTHIC_MOBS_SKILL; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map args) { + String skill = ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("skill"), "warning.config.function.mythic_mobs_skill.missing_skill"); + float power = ResourceConfigUtils.getAsFloat(args.getOrDefault("power", 1.0), "power"); + return new MythicMobsSkillFunction<>(skill, power, getPredicates(args)); + } + } +} From 56226e1ad99873ac4609c4c0e752d2a1e4022d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sun, 20 Jul 2025 21:08:09 +0800 Subject: [PATCH 23/83] fix: DoubleLoreModifier --- .../craftengine/core/item/modifier/lore/LoreModifier.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java index 912e4d099..8e998115d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java @@ -105,10 +105,7 @@ public sealed interface LoreModifier extends ItemDataModifier @Override public Item apply(Item item, ItemBuildContext context) { - Stream start = Stream.empty(); - this.modification1.apply(start, context); - this.modification2.apply(start, context); - item.loreComponent(start.toList()); + item.loreComponent(this.modification2.apply(this.modification1.apply(Stream.empty(), context), context).toList()); return item; } } From bee6d258b4ca8b99fc090d4cb87b6e0ec82bd158 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 20 Jul 2025 21:23:32 +0800 Subject: [PATCH 24/83] =?UTF-8?q?=E4=B9=9F=E8=AE=B8=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BA=86FAWE=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 12 +- ...ngineItemDrop.java => MythicItemDrop.java} | 4 +- ...tener.java => MythicItemDropListener.java} | 6 +- ...killHelper.java => MythicSkillHelper.java} | 6 +- .../worldedit/FastAsyncWorldEditDelegate.java | 38 +++--- .../bukkit/world/BukkitWorldManager.java | 118 +++++++++--------- .../compatibility/CompatibilityManager.java | 2 +- .../function/MythicMobsSkillFunction.java | 2 +- .../craftengine/core/world/WorldManager.java | 2 + gradle.properties | 2 +- 10 files changed, 103 insertions(+), 89 deletions(-) rename bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/{CraftEngineItemDrop.java => MythicItemDrop.java} (93%) rename bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/{MythicMobsListener.java => MythicItemDropListener.java} (83%) rename bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/{SkillHelper.java => MythicSkillHelper.java} (81%) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index 56248a777..a341e41fe 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -10,8 +10,8 @@ import net.momirealms.craftengine.bukkit.compatibility.leveler.*; import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelModel; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils; -import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicMobsListener; -import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.SkillHelper; +import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDropListener; +import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicSkillHelper; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners; import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook; @@ -40,7 +40,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager { private final Map levelerProviders; private boolean hasPlaceholderAPI; private boolean hasViaVersion; - private SkillHelper skillExecute; + private MythicSkillHelper skillExecute; public BukkitCompatibilityManager(BukkitCraftEngine plugin) { this.plugin = plugin; @@ -133,14 +133,14 @@ public class BukkitCompatibilityManager implements CompatibilityManager { } if (this.isPluginEnabled("MythicMobs")) { BukkitItemManager.instance().registerExternalItemSource(new MythicMobsSource()); - new MythicMobsListener(this.plugin); + new MythicItemDropListener(this.plugin); logHook("MythicMobs"); } } @Override - public void skillExecute(String skill, float power, Player player) { - SkillHelper.execute(skill, power, player); + public void executeMMSkill(String skill, float power, Player player) { + MythicSkillHelper.execute(skill, power, player); } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java similarity index 93% rename from bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java index 9c582cf1d..8b151df79 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java @@ -21,12 +21,12 @@ import org.bukkit.inventory.ItemStack; import java.lang.reflect.Constructor; -public class CraftEngineItemDrop extends ItemDrop implements IItemDrop { +public class MythicItemDrop extends ItemDrop implements IItemDrop { private final CustomItem customItem; private static final Constructor constructor$BukkitItemStack = ReflectionUtils.getConstructor(BukkitItemStack.class, ItemStack.class); private static final boolean useReflection = constructor$BukkitItemStack != null; - public CraftEngineItemDrop(String line, MythicLineConfig config, CustomItem customItem) { + public MythicItemDrop(String line, MythicLineConfig config, CustomItem customItem) { super(line, config); this.customItem = customItem; } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java similarity index 83% rename from bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java index 22101993b..96cacc0b7 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java @@ -8,10 +8,10 @@ import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -public class MythicMobsListener implements Listener { +public class MythicItemDropListener implements Listener { private final BukkitCraftEngine plugin; - public MythicMobsListener(BukkitCraftEngine plugin) { + public MythicItemDropListener(BukkitCraftEngine plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin()); } @@ -24,7 +24,7 @@ public class MythicMobsListener implements Listener { this.plugin.itemManager().getCustomItem(itemId).ifPresent(customItem -> { String line = event.getContainer().getConfigLine(); MythicLineConfig config = event.getConfig(); - event.register(new CraftEngineItemDrop(line, config, customItem)); + event.register(new MythicItemDrop(line, config, customItem)); }); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicSkillHelper.java similarity index 81% rename from bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicSkillHelper.java index 32162b6d2..8ac5a7356 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicSkillHelper.java @@ -10,7 +10,7 @@ import org.bukkit.entity.LivingEntity; import java.util.ArrayList; import java.util.List; -public class SkillHelper { +public final class MythicSkillHelper { public static void execute(String skill, float power, Player player) { org.bukkit.entity.Player casterPlayer = (org.bukkit.entity.Player) player.platformPlayer(); @@ -22,8 +22,6 @@ public class SkillHelper { targets.add(target); locations = List.of(target.getLocation()); } - try (MythicBukkit mm = MythicBukkit.inst()) { - mm.getAPIHelper().castSkill(casterPlayer, skill, casterPlayer, location, targets, locations, power); - } + MythicBukkit.inst().getAPIHelper().castSkill(casterPlayer, skill, casterPlayer, location, targets, locations, power); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java index b03240f25..476e6370c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java @@ -1,9 +1,12 @@ package net.momirealms.craftengine.bukkit.compatibility.worldedit; +import com.fastasyncworldedit.bukkit.FaweBukkitWorld; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; +import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.ExtentTraverser; import com.fastasyncworldedit.core.util.ProcessorTraverser; import com.sk89q.worldedit.EditSession; @@ -24,6 +27,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.WorldStorageInjector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.EmptyBlock; @@ -41,6 +45,8 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.lang.reflect.Method; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import static java.util.Objects.requireNonNull; @@ -89,12 +95,14 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { if (levelChunk != null) { Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); CESection[] ceSections = ceChunk.sections(); - for (int i = 0; i < ceSections.length; i++) { - CESection ceSection = ceSections[i]; - Object section = sections[i]; - int finalI = i; - WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), - (injected) -> sections[finalI] = injected); + synchronized (sections) { + for (int i = 0; i < ceSections.length; i++) { + CESection ceSection = ceSections[i]; + Object section = sections[i]; + int finalI = i; + WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), + (injected) -> sections[finalI] = injected); + } } } } @@ -174,18 +182,18 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { @Override public @Nullable Operation commit() { - Operation operation = super.commit(); saveAllChunks(); + Operation operation = super.commit(); List chunks = new ArrayList<>(this.brokenChunks); this.brokenChunks.clear(); - Object worldServer = this.ceWorld.world().serverWorld(); - Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); - for (ChunkPos chunk : chunks) { - CEChunk loaded = this.ceWorld.getChunkAtIfLoaded(chunk.longKey()); - // only inject loaded chunks - if (loaded == null) continue; - injectLevelChunk(chunkSource, loaded); - } + Object worldServer = this.ceWorld.world().serverWorld(); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); + for (ChunkPos chunk : chunks) { + CEChunk loaded = this.ceWorld.getChunkAtIfLoaded(chunk.longKey()); + // only inject loaded chunks + if (loaded == null) continue; + injectLevelChunk(chunkSource, loaded); + } return operation; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 61aa6dabb..bd04de0e4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -88,6 +88,11 @@ public class BukkitWorldManager implements WorldManager, Listener { } } + @Override + public CEWorld[] getWorlds() { + return this.worldArray; + } + private void resetWorldArray() { this.worldArray = this.worlds.values().toArray(new CEWorld[0]); } @@ -218,7 +223,6 @@ public class BukkitWorldManager implements WorldManager, Listener { this.lastVisitedUUID = null; } this.resetWorldArray(); - } finally { this.worldMapLock.writeLock().unlock(); } @@ -328,74 +332,76 @@ public class BukkitWorldManager implements WorldManager, Listener { Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); - for (int i = 0; i < ceSections.length; i++) { - CESection ceSection = ceSections[i]; - Object section = sections[i]; - if (Config.syncCustomBlocks()) { - Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section); - Object data = CoreReflections.varHandle$PalettedContainer$data.get(statesContainer); - Object palette = CoreReflections.field$PalettedContainer$Data$palette.get(data); - boolean requiresSync = false; - if (CoreReflections.clazz$SingleValuePalette.isInstance(palette)) { - Object onlyBlockState = CoreReflections.field$SingleValuePalette$value.get(palette); - if (BlockStateUtils.isCustomBlock(onlyBlockState)) { + synchronized (sections) { + for (int i = 0; i < ceSections.length; i++) { + CESection ceSection = ceSections[i]; + Object section = sections[i]; + if (Config.syncCustomBlocks()) { + Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section); + Object data = CoreReflections.varHandle$PalettedContainer$data.get(statesContainer); + Object palette = CoreReflections.field$PalettedContainer$Data$palette.get(data); + boolean requiresSync = false; + if (CoreReflections.clazz$SingleValuePalette.isInstance(palette)) { + Object onlyBlockState = CoreReflections.field$SingleValuePalette$value.get(palette); + if (BlockStateUtils.isCustomBlock(onlyBlockState)) { + requiresSync = true; + } + } else if (CoreReflections.clazz$LinearPalette.isInstance(palette)) { + Object[] blockStates = (Object[]) CoreReflections.field$LinearPalette$values.get(palette); + for (Object blockState : blockStates) { + if (blockState != null) { + if (BlockStateUtils.isCustomBlock(blockState)) { + requiresSync = true; + break; + } + } + } + } else if (CoreReflections.clazz$HashMapPalette.isInstance(palette)) { + Object biMap = CoreReflections.field$HashMapPalette$values.get(palette); + Object[] blockStates = (Object[]) CoreReflections.field$CrudeIncrementalIntIdentityHashBiMap$keys.get(biMap); + for (Object blockState : blockStates) { + if (blockState != null) { + if (BlockStateUtils.isCustomBlock(blockState)) { + requiresSync = true; + break; + } + } + } + } else { requiresSync = true; } - } else if (CoreReflections.clazz$LinearPalette.isInstance(palette)) { - Object[] blockStates = (Object[]) CoreReflections.field$LinearPalette$values.get(palette); - for (Object blockState : blockStates) { - if (blockState != null) { - if (BlockStateUtils.isCustomBlock(blockState)) { - requiresSync = true; - break; - } - } - } - } else if (CoreReflections.clazz$HashMapPalette.isInstance(palette)) { - Object biMap = CoreReflections.field$HashMapPalette$values.get(palette); - Object[] blockStates = (Object[]) CoreReflections.field$CrudeIncrementalIntIdentityHashBiMap$keys.get(biMap); - for (Object blockState : blockStates) { - if (blockState != null) { - if (BlockStateUtils.isCustomBlock(blockState)) { - requiresSync = true; - break; - } - } - } - } else { - requiresSync = true; - } - if (requiresSync) { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 16; y++) { - Object mcState = FastNMS.INSTANCE.method$LevelChunkSection$getBlockState(section, x, y, z); - Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(mcState); - if (optionalCustomState.isPresent()) { - ceSection.setBlockState(x, y, z, optionalCustomState.get()); + if (requiresSync) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 16; y++) { + Object mcState = FastNMS.INSTANCE.method$LevelChunkSection$getBlockState(section, x, y, z); + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(mcState); + if (optionalCustomState.isPresent()) { + ceSection.setBlockState(x, y, z, optionalCustomState.get()); + } } } } } } - } - if (Config.restoreCustomBlocks()) { - if (!ceSection.statesContainer().isEmpty()) { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 16; y++) { - ImmutableBlockState customState = ceSection.getBlockState(x, y, z); - if (!customState.isEmpty() && customState.customBlockState() != null) { - FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().handle(), false); + if (Config.restoreCustomBlocks()) { + if (!ceSection.statesContainer().isEmpty()) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 16; y++) { + ImmutableBlockState customState = ceSection.getBlockState(x, y, z); + if (!customState.isEmpty() && customState.customBlockState() != null) { + FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().handle(), false); + } } } } } } + int finalI = i; + WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), + (injected) -> sections[finalI] = injected); } - int finalI = i; - WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), - (injected) -> sections[finalI] = injected); } if (Config.enableRecipeSystem()) { @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java index 9459acdfc..f38d30c1f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java @@ -35,5 +35,5 @@ public interface CompatibilityManager { int getPlayerProtocolVersion(UUID uuid); - void skillExecute(String skill, float power, Player player); + void executeMMSkill(String skill, float power, Player player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java index bb4a61c85..031ed08da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java @@ -23,7 +23,7 @@ public class MythicMobsSkillFunction extends AbstractCondit @Override protected void runInternal(CTX ctx) { ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { - CraftEngine.instance().compatibilityManager().skillExecute(this.skill, this.power, it); + CraftEngine.instance().compatibilityManager().executeMMSkill(this.skill, this.power, it); }); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index 5c83b592b..d6a746cbd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -13,6 +13,8 @@ public interface WorldManager extends Manageable { CEWorld getWorld(UUID uuid); + CEWorld[] getWorlds(); + void loadWorld(World world); void loadWorld(CEWorld world); diff --git a/gradle.properties b/gradle.properties index 1e4e87a6e..2c126627e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.4 +project_version=0.0.60.5 config_version=43 lang_version=22 project_group=net.momirealms From 8de1acc3ee5712e01eb9f55c00b5e41e7fe20184 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 21 Jul 2025 04:54:45 +0800 Subject: [PATCH 25/83] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=BD=BF=E7=94=A8secti?= =?UTF-8?q?on=E4=BF=AE=E5=A4=8D=E6=BD=9C=E5=9C=A8=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../worldedit/FastAsyncWorldEditDelegate.java | 7 +++---- common-files/src/main/resources/config.yml | 6 ++---- .../craftengine/core/item/AbstractItemManager.java | 1 + .../momirealms/craftengine/core/world/chunk/CEChunk.java | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java index 476e6370c..04669495f 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java @@ -45,8 +45,6 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.lang.reflect.Method; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; import static java.util.Objects.requireNonNull; @@ -222,11 +220,12 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { try { CEChunk ceChunk = Optional.ofNullable(this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ)) .orElse(this.ceWorld.worldDataStorage().readChunkAt(this.ceWorld, new ChunkPos(chunkX, chunkZ))); + CESection ceSection = ceChunk.sectionById(SectionPos.blockToSectionCoord(blockY)); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(newStateId); if (immutableBlockState == null) { - ceChunk.setBlockState(blockX, blockY, blockZ, EmptyBlock.STATE); + ceSection.setBlockState(blockX & 15, blockY & 15, blockZ & 15, EmptyBlock.STATE); } else { - ceChunk.setBlockState(blockX, blockY, blockZ, immutableBlockState); + ceSection.setBlockState(blockX & 15, blockY & 15, blockZ & 15, immutableBlockState); } this.chunksToSave.add(ceChunk); } catch (IOException e) { diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 5acc916c1..9222673b8 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -84,8 +84,6 @@ resource-pack: ip: "localhost" port: 8163 protocol: "http" - # The optional URL must be complete and include a trailing slash / at the end. - #url: "http://localhost:8163/" deny-non-minecraft-request: true one-time-token: true rate-limit: @@ -380,9 +378,9 @@ chunk-system: # Settings for injection injection: # Requires a restart to apply - # SECTION: Inject the LevelChunkSection (Faster & Experimental) since 0.0.53 + # SECTION: Inject the LevelChunkSection # PALETTE: Inject the PalettedContainer - target: PALETTE + target: SECTION # Enables faster injection method # Note: May not work with certain server forks that alter chunk class structure (In most cases it won't conflict) use-fast-method: false diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 0bb7a59cf..6865d2cf7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -16,6 +16,7 @@ import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; +import net.momirealms.craftengine.core.pack.host.ResourcePackHosts; import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java index 45b0a52b8..fb00cc0dc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java @@ -113,7 +113,7 @@ public class CEChunk { return this.sections[index]; } - @Nullable + @NotNull public CESection sectionById(int sectionId) { return this.sections[sectionIndex(sectionId)]; } From feb86deaaf2f1aeb11c1bf107bc2a8af71e957a5 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 21 Jul 2025 05:03:01 +0800 Subject: [PATCH 26/83] =?UTF-8?q?fix(item):=20=E4=BF=AE=E5=A4=8D=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E5=BE=88=E6=8A=BD=E8=B1=A1=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/item/ModernNetworkItemHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index b94a64568..15b134f3e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -60,6 +60,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler> s2c(Item wrapped, Player player) { + Item original = wrapped; Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) { if (!Config.interceptItem()) return Optional.empty(); @@ -89,7 +90,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler modifier : customItem.clientBoundDataModifiers()) { - modifier.prepareNetworkItem(wrapped, context, tag); + modifier.prepareNetworkItem(original, context, tag); } for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { modifier.apply(wrapped, context); From 9a1ebd8b58909dec0ae9e7669a64787a00828511 Mon Sep 17 00:00:00 2001 From: halogly Date: Mon, 21 Jul 2025 11:19:52 +0800 Subject: [PATCH 27/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9tag=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E5=AE=9E=E4=BD=93=E4=BD=BF=E7=94=A8=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/util/EntityUtils.java | 37 +++---- .../bukkit/util/InteractUtils.java | 96 ++++++++++--------- .../craftengine/bukkit/util/ItemTags.java | 10 -- .../craftengine/core/entity/EntityKeys.java | 34 +++++++ 4 files changed, 103 insertions(+), 74 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index 070dd8ebe..2772f445e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.core.item.Item; @@ -8,12 +9,8 @@ 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.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -21,7 +18,8 @@ import java.util.function.Consumer; public class EntityUtils { - private EntityUtils() {} + private EntityUtils() { + } public static BlockPos getOnPos(Player player) { try { @@ -41,6 +39,13 @@ public class EntityUtils { } } + public static boolean isPetOwner(Player player, Entity entity) { + if (!(entity instanceof Sittable sittable)) return false; + return sittable instanceof Tameable tameable + && tameable.isTamed() + && tameable.getOwnerUniqueId() == player.getUniqueId(); + } + public static boolean isPiglinWithGoldIngot(Entity entity, Item item) { return entity.getType() == EntityType.PIGLIN && item != null && @@ -48,16 +53,12 @@ public class EntityUtils { } public static boolean isHappyGhastRideable(Entity entity) { - if (!VersionHelper.isOrAbove1_21_6() && - !entity.getType().name().equals("HAPPY_GHAST")) return false; - return entity instanceof LivingEntity livingEntity - && livingEntity.getEquipment() != null - && hasHarness(livingEntity.getEquipment()); + if (!VersionHelper.isOrAbove1_21_6()) return false; + if (entity instanceof LivingEntity living && entity.getType() == EntityType.HAPPY_GHAST) { + ItemStack bodyItem = living.getEquipment().getItem(EquipmentSlot.BODY); + Item wrapped = BukkitItemManager.instance().wrap(bodyItem); + return wrapped.is(Key.of("harnesses")); + } + return false; } - - public static boolean hasHarness(EntityEquipment equipment) { - ItemStack bodyItem = equipment.getItem(EquipmentSlot.BODY); - return ItemTags.ITEMS_HARNESSES != null && - ItemTags.ITEMS_HARNESSES.isTagged(bodyItem.getType()); - } -} +} \ No newline at end of file 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 99b3398a2..9ff03e35c 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 @@ -1,7 +1,9 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.block.BlockKeys; +import net.momirealms.craftengine.core.entity.EntityKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; @@ -29,7 +31,7 @@ public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); private static final Map, BlockData, BlockHitResult, Boolean>> WILL_CONSUME = new HashMap<>(); private static final Key NOTE_BLOCK_TOP_INSTRUMENTS = Key.of("minecraft:noteblock_top_instruments"); - private static final Set INTERACTABLE_ENTITIES = createInteractableEntities(); + private static final Set INTERACTABLE_ENTITIES = new HashSet<>(); private InteractUtils() {} @@ -92,12 +94,8 @@ public class InteractUtils { ))) != null; }); registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> { - Direction direction = result.getDirection(); - if (blockState instanceof ChiseledBookshelf chiseledBookshelf) { - Direction facing = DirectionUtils.toDirection(chiseledBookshelf.getFacing()); - return facing == direction; - } - return false; + if (!(blockState instanceof ChiseledBookshelf chiseledBookshelf)) return false; + return DirectionUtils.toDirection(chiseledBookshelf.getFacing()) == result.getDirection(); }); registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); @@ -287,31 +285,35 @@ public class InteractUtils { result.getDirection() == Direction.UP && item.id().equals(ItemKeys.CACTUS)); } - private static Set createInteractableEntities() { - Set set = EnumSet.noneOf(EntityType.class); - set.addAll(Set.of( - EntityType.ALLAY, - EntityType.HORSE, - EntityType.ZOMBIE_HORSE, - EntityType.SKELETON_HORSE, - EntityType.DONKEY, - EntityType.MULE, - EntityType.VILLAGER, - EntityType.WANDERING_TRADER, - EntityType.LLAMA, - EntityType.TRADER_LLAMA, - EntityType.CAMEL, - EntityType.CHEST_MINECART, - EntityType.FURNACE_MINECART, - EntityType.HOPPER_MINECART, - EntityType.COMMAND_BLOCK_MINECART, - EntityType.ITEM_FRAME, - EntityType.GLOW_ITEM_FRAME - )); - if (VersionHelper.isOrAbove1_21_6()) { - set.add(EntityType.valueOf("HAPPY_GHAST")); + static { + registerInteractableEntity(EntityKeys.ALLAY); + registerInteractableEntity(EntityKeys.HORSE); + registerInteractableEntity(EntityKeys.ZOMBIE_HORSE); + registerInteractableEntity(EntityKeys.SKELETON_HORSE); + registerInteractableEntity(EntityKeys.DONKEY); + registerInteractableEntity(EntityKeys.MULE); + registerInteractableEntity(EntityKeys.VILLAGER); + registerInteractableEntity(EntityKeys.WANDERING_TRADER); + registerInteractableEntity(EntityKeys.LLAMA); + registerInteractableEntity(EntityKeys.TRADER_LLAMA); + registerInteractableEntity(EntityKeys.CAMEL); + registerInteractableEntity(EntityKeys.ITEM_FRAME); + registerInteractableEntity(EntityKeys.GLOW_ITEM_FRAME); + registerInteractableEntity(EntityKeys.INTERACTION); + if (VersionHelper.isOrAbove1_20_5()) { + registerInteractableEntity(EntityKeys.CHEST_MINECART); + registerInteractableEntity(EntityKeys.FURNACE_MINECART); + registerInteractableEntity(EntityKeys.HOPPER_MINECART); + registerInteractableEntity(EntityKeys.COMMAND_BLOCK_MINECART); + } else { + registerInteractableEntity(EntityKeys.MINECART_CHEST); + registerInteractableEntity(EntityKeys.MINECART_FURNACE); + registerInteractableEntity(EntityKeys.MINECART_HOPPER); + registerInteractableEntity(EntityKeys.MINECART_COMMAND); + } + if (VersionHelper.isOrAbove1_21_6()) { + registerInteractableEntity(EntityKeys.HAPPY_GHAST); } - return Collections.unmodifiableSet(set); } private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { @@ -328,6 +330,13 @@ public class InteractUtils { } } + private static void registerInteractableEntity(Key key) { + var previous = INTERACTABLE_ENTITIES.add(key); + if (!previous) { + CraftEngine.instance().logger().warn("Duplicated interaction check: " + key); + } + } + public static boolean isInteractable(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state); if (INTERACTIONS.containsKey(blockType)) { @@ -338,22 +347,17 @@ public class InteractUtils { } public static boolean isEntityInteractable(Player player, Entity entity, Item item) { - if (EntityUtils.isPiglinWithGoldIngot(entity, item)) { - return true; - } +// Object entityType = FastNMS.INSTANCE.method$CraftEntityType$toNMSEntityType(entity.getType()); + Key entityType = Key.of(String.valueOf(entity.getType())); + if (EntityUtils.isPetOwner(player, entity)) return true; + if (EntityUtils.isPiglinWithGoldIngot(entity, item)) return true; if (!player.isSneaking()) { - if (EntityUtils.isHappyGhastRideable(entity)) { - return true; - } - return switch (entity) { - case Boat ignored -> true; - case RideableMinecart ignored -> true; - case Steerable steerable -> steerable.hasSaddle(); - default -> INTERACTABLE_ENTITIES.contains(entity.getType()); - }; + if (EntityUtils.isHappyGhastRideable(entity)) return true; + if (entity instanceof Boat) return true; + if (entity instanceof RideableMinecart) return true; + if (entity instanceof Steerable steerable && steerable.hasSaddle()) return true; } - return entity instanceof ChestBoat - || INTERACTABLE_ENTITIES.contains(entity.getType()); + return entity instanceof ChestBoat || INTERACTABLE_ENTITIES.contains(entityType); } public static boolean willConsume(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { @@ -365,7 +369,7 @@ public class InteractUtils { return false; } } - + private static boolean canEat(Player player, boolean ignoreHunger) { return ignoreHunger || player.isInvulnerable() || player.getFoodLevel() < 20; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java index 62ab60190..6028485a4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java @@ -17,7 +17,6 @@ public class ItemTags { public static final Key AXES = Key.of("minecraft:axes"); public static final Key SWORDS = Key.of("minecraft:swords"); - public static final Tag ITEMS_HARNESSES = getHarnessTag(); private ItemTags() {} @@ -29,13 +28,4 @@ public class ItemTags { } return value; } - - public static Tag getHarnessTag() { - if (!VersionHelper.isOrAbove1_21_6()) return null; - try { - return Bukkit.getTag("items", NamespacedKey.minecraft("harnesses"), Material.class); - } catch (Exception e) { - return null; - } - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java new file mode 100644 index 000000000..4b34d4c20 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java @@ -0,0 +1,34 @@ +package net.momirealms.craftengine.core.entity; + +import net.momirealms.craftengine.core.util.Key; + +public class EntityKeys { + private EntityKeys() {} + + public static final Key ALLAY = Key.of("minecraft:ALLAY"); + public static final Key HORSE = Key.of("minecraft:HORSE"); + public static final Key ZOMBIE_HORSE = Key.of("minecraft:ZOMBIE_HORSE"); + public static final Key SKELETON_HORSE = Key.of("minecraft:SKELETON_HORSE"); + public static final Key DONKEY = Key.of("minecraft:DONKEY"); + public static final Key MULE = Key.of("minecraft:MULE"); + public static final Key VILLAGER = Key.of("minecraft:VILLAGER"); + public static final Key WANDERING_TRADER = Key.of("minecraft:WANDERING_TRADER"); + public static final Key LLAMA = Key.of("minecraft:LLAMA"); + public static final Key TRADER_LLAMA = Key.of("minecraft:TRADER_LLAMA"); + public static final Key CAMEL = Key.of("minecraft:CAMEL"); + public static final Key ITEM_FRAME = Key.of("minecraft:ITEM_FRAME"); + public static final Key GLOW_ITEM_FRAME = Key.of("minecraft:GLOW_ITEM_FRAME"); + public static final Key INTERACTION = Key.of("minecraft:INTERACTION"); + // ≥1.20.5 + public static final Key CHEST_MINECART = Key.of("minecraft:CHEST_MINECART"); + public static final Key FURNACE_MINECART = Key.of("minecraft:FURNACE_MINECART"); + public static final Key HOPPER_MINECART = Key.of("minecraft:HOPPER_MINECART"); + public static final Key COMMAND_BLOCK_MINECART = Key.of("minecraft:COMMAND_BLOCK_MINECART"); + // <1.20.5 + public static final Key MINECART_CHEST = Key.of("minecraft:MINECART_CHEST"); + public static final Key MINECART_FURNACE = Key.of("minecraft:MINECART_FURNACE"); + public static final Key MINECART_HOPPER = Key.of("minecraft:MINECART_HOPPER"); + public static final Key MINECART_COMMAND = Key.of("minecraft:MINECART_COMMAND"); + // ≥1.21.6 + public static final Key HAPPY_GHAST = Key.of("minecraft:HAPPY_GHAST"); +} From 4ed2694ade5bd39bc17939716ca7cb5e2f2a10c5 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 21 Jul 2025 17:07:32 +0800 Subject: [PATCH 28/83] Update config.yml --- common-files/src/main/resources/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 9222673b8..ca645f6ba 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -383,7 +383,7 @@ chunk-system: target: SECTION # Enables faster injection method # Note: May not work with certain server forks that alter chunk class structure (In most cases it won't conflict) - use-fast-method: false + use-fast-method: true # Auto-convert custom blocks -> vanilla blocks when unloading chunks # # - When ENABLED (true): From a53875f331a8f9064ce3202acec4f7615670bfb1 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 21 Jul 2025 20:30:42 +0800 Subject: [PATCH 29/83] =?UTF-8?q?refactor(core):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=89=A9=E5=93=81=E9=9A=90=E8=97=8F=E5=B1=9E=E6=80=A7=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/modifier/HideTooltipModifier.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java index 20c2bab7c..2748c84ad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java @@ -20,6 +20,17 @@ import java.util.stream.Stream; public class HideTooltipModifier implements ItemDataModifier { public static final Map TO_LEGACY; + public static final List COMPONENTS = List.of( + ComponentKeys.UNBREAKABLE, + ComponentKeys.ENCHANTMENTS, + ComponentKeys.STORED_ENCHANTMENTS, + ComponentKeys.CAN_PLACE_ON, + ComponentKeys.CAN_BREAK, + ComponentKeys.ATTRIBUTE_MODIFIERS, + ComponentKeys.DYED_COLOR, + ComponentKeys.TRIM, + ComponentKeys.JUKEBOX_PLAYABLE + ); static { ImmutableMap.Builder builder = ImmutableMap.builder(); builder.put(ComponentKeys.ENCHANTMENTS, 1); @@ -51,11 +62,12 @@ public class HideTooltipModifier implements ItemDataModifier { } else if (VersionHelper.isOrAbove1_20_5()) { if (components.isEmpty()) { this.applier = new DummyApplier<>(); - } else if (components.size() == 1) { + } else if (components.size() == 1 && COMPONENTS.contains(components.getFirst())) { this.applier = new SemiModernApplier<>(components.getFirst()); } else { List> appliers = new ArrayList<>(); for (Key key : components) { + if (!COMPONENTS.contains(key)) continue; appliers.add(new SemiModernApplier<>(key)); } this.applier = new CompoundApplier<>(appliers); @@ -134,10 +146,6 @@ public class HideTooltipModifier implements ItemDataModifier { if (previous instanceof CompoundTag compoundTag) { compoundTag.putBoolean("show_in_tooltip", false); item.setNBTComponent(this.component, compoundTag); - } else { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putBoolean("show_in_tooltip", false); - item.setNBTComponent(this.component, compoundTag); } } } From c8f786a7577c15be9cc6677844cbf5c8ad2339a7 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 21 Jul 2025 22:14:13 +0800 Subject: [PATCH 30/83] =?UTF-8?q?refactor(core):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=89=A9=E5=93=81=E9=9A=90=E8=97=8F=E5=B1=9E=E6=80=A7=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/modifier/HideTooltipModifier.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java index 2748c84ad..cd1cc3288 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java @@ -62,15 +62,25 @@ public class HideTooltipModifier implements ItemDataModifier { } else if (VersionHelper.isOrAbove1_20_5()) { if (components.isEmpty()) { this.applier = new DummyApplier<>(); - } else if (components.size() == 1 && COMPONENTS.contains(components.getFirst())) { - this.applier = new SemiModernApplier<>(components.getFirst()); + } else if (components.size() == 1) { + if (COMPONENTS.contains(components.getFirst())) { + this.applier = new SemiModernApplier<>(components.getFirst()); + } else { + this.applier = new DummyApplier<>(); + } } else { List> appliers = new ArrayList<>(); for (Key key : components) { if (!COMPONENTS.contains(key)) continue; appliers.add(new SemiModernApplier<>(key)); } - this.applier = new CompoundApplier<>(appliers); + if (appliers.isEmpty()) { + this.applier = new DummyApplier<>(); + } else if (appliers.size() == 1) { + this.applier = new SemiModernApplier<>(components.getFirst()); + } else { + this.applier = new CompoundApplier<>(appliers); + } } } else { this.applier = new LegacyApplier<>(components); From 99cd3a52eab0ca0666078e9eaff330e07e7657d6 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 21 Jul 2025 22:15:31 +0800 Subject: [PATCH 31/83] =?UTF-8?q?refactor(core):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=89=A9=E5=93=81=E9=9A=90=E8=97=8F=E5=B1=9E=E6=80=A7=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/item/modifier/HideTooltipModifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java index cd1cc3288..4b56b6b74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java @@ -77,7 +77,7 @@ public class HideTooltipModifier implements ItemDataModifier { if (appliers.isEmpty()) { this.applier = new DummyApplier<>(); } else if (appliers.size() == 1) { - this.applier = new SemiModernApplier<>(components.getFirst()); + this.applier = appliers.getFirst(); } else { this.applier = new CompoundApplier<>(appliers); } From e7a2386466b78a14e1407d7f68dfc5df371681de Mon Sep 17 00:00:00 2001 From: halogly Date: Tue, 22 Jul 2025 18:08:19 +0800 Subject: [PATCH 32/83] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E4=B8=80=E5=A0=86if?= =?UTF-8?q?=E5=88=A4=E6=96=AD=EF=BC=8C=E4=BD=BF=E7=94=A8=E6=98=A0=E5=B0=84?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=8F=AF=E4=BA=A4=E4=BA=92=E5=AE=9E=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/InteractUtils.java | 114 ++++++++++-------- .../craftengine/core/entity/EntityKeys.java | 33 ++++- 2 files changed, 97 insertions(+), 50 deletions(-) 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 9ff03e35c..ea50ffd26 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 @@ -14,14 +14,13 @@ 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.VersionHelper; +import net.momirealms.craftengine.core.util.TriFunction; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bell; import org.bukkit.block.data.type.ChiseledBookshelf; import org.bukkit.entity.*; -import org.bukkit.entity.minecart.RideableMinecart; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; @@ -31,7 +30,7 @@ public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); private static final Map, BlockData, BlockHitResult, Boolean>> WILL_CONSUME = new HashMap<>(); private static final Key NOTE_BLOCK_TOP_INSTRUMENTS = Key.of("minecraft:noteblock_top_instruments"); - private static final Set INTERACTABLE_ENTITIES = new HashSet<>(); + private static final Map, Boolean>> ENTITY_INTERACTIONS = new HashMap<>(); private InteractUtils() {} @@ -286,34 +285,63 @@ public class InteractUtils { } static { - registerInteractableEntity(EntityKeys.ALLAY); - registerInteractableEntity(EntityKeys.HORSE); - registerInteractableEntity(EntityKeys.ZOMBIE_HORSE); - registerInteractableEntity(EntityKeys.SKELETON_HORSE); - registerInteractableEntity(EntityKeys.DONKEY); - registerInteractableEntity(EntityKeys.MULE); - registerInteractableEntity(EntityKeys.VILLAGER); - registerInteractableEntity(EntityKeys.WANDERING_TRADER); - registerInteractableEntity(EntityKeys.LLAMA); - registerInteractableEntity(EntityKeys.TRADER_LLAMA); - registerInteractableEntity(EntityKeys.CAMEL); - registerInteractableEntity(EntityKeys.ITEM_FRAME); - registerInteractableEntity(EntityKeys.GLOW_ITEM_FRAME); - registerInteractableEntity(EntityKeys.INTERACTION); - if (VersionHelper.isOrAbove1_20_5()) { - registerInteractableEntity(EntityKeys.CHEST_MINECART); - registerInteractableEntity(EntityKeys.FURNACE_MINECART); - registerInteractableEntity(EntityKeys.HOPPER_MINECART); - registerInteractableEntity(EntityKeys.COMMAND_BLOCK_MINECART); - } else { - registerInteractableEntity(EntityKeys.MINECART_CHEST); - registerInteractableEntity(EntityKeys.MINECART_FURNACE); - registerInteractableEntity(EntityKeys.MINECART_HOPPER); - registerInteractableEntity(EntityKeys.MINECART_COMMAND); - } - if (VersionHelper.isOrAbove1_21_6()) { - registerInteractableEntity(EntityKeys.HAPPY_GHAST); - } + // 忽视潜行的交互实体 + registerEntityInteraction(EntityKeys.ALLAY, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.HORSE, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.ZOMBIE_HORSE, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.SKELETON_HORSE, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.DONKEY, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.MULE, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.VILLAGER, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.WANDERING_TRADER, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.LLAMA, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.TRADER_LLAMA, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.CAMEL, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.ITEM_FRAME, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.GLOW_ITEM_FRAME, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.INTERACTION, (player, entity, item) -> true); + // 潜行时不可交互 + registerEntityInteraction(EntityKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.BAMBOO_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.CHERRY_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.DARK_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.JUNGLE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.MANGROVE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.SPRUCE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.MINECART, (player, entity, item) -> !player.isSneaking()); + // 始终可交互的箱子类船车 + registerEntityInteraction(EntityKeys.ACACIA_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.BAMBOO_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.BIRCH_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.CHERRY_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.DARK_OAK_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.JUNGLE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.MANGROVE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.OAK_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.SPRUCE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.CHEST_MINECART, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.FURNACE_MINECART, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.HOPPER_MINECART, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.COMMAND_BLOCK_MINECART, (player, entity, item) -> true); + //<1.20.5 + registerEntityInteraction(EntityKeys.MINECART_CHEST, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.MINECART_HOPPER, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.MINECART_FURNACE, (player, entity, item) -> true); + registerEntityInteraction(EntityKeys.MINECART_COMMAND, (player, entity, item) -> true); + // 有鞍 + 非潜行可交互(如猪、炽足兽) + registerEntityInteraction(EntityKeys.PIG, (player, entity, item) -> + entity instanceof Steerable steerable && steerable.hasSaddle() && !player.isSneaking()); + registerEntityInteraction(EntityKeys.STRIDER, (player, entity, item) -> + entity instanceof Steerable steerable && steerable.hasSaddle() && !player.isSneaking()); + // 是宠物,且主人是玩家(忽视潜行) + registerEntityInteraction(EntityKeys.WOLF, (player, entity, item) -> EntityUtils.isPetOwner(player, entity)); + registerEntityInteraction(EntityKeys.CAT, (player, entity, item) -> EntityUtils.isPetOwner(player, entity)); + registerEntityInteraction(EntityKeys.PARROT, (player, entity, item) -> EntityUtils.isPetOwner(player, entity)); + // 快乐恶魂(装备挽具、受潜行影响) + registerEntityInteraction(EntityKeys.HAPPY_GHAST, (player, entity, item) -> + EntityUtils.isHappyGhastRideable(entity) && !player.isSneaking()); } private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { @@ -330,10 +358,10 @@ public class InteractUtils { } } - private static void registerInteractableEntity(Key key) { - var previous = INTERACTABLE_ENTITIES.add(key); - if (!previous) { - CraftEngine.instance().logger().warn("Duplicated interaction check: " + key); + private static void registerEntityInteraction(Key key, TriFunction, Boolean> function) { + var previous = ENTITY_INTERACTIONS.put(key, function); + if (previous != null) { + CraftEngine.instance().logger().warn("Duplicated entity interaction check: " + key); } } @@ -346,18 +374,10 @@ public class InteractUtils { } } - public static boolean isEntityInteractable(Player player, Entity entity, Item item) { -// Object entityType = FastNMS.INSTANCE.method$CraftEntityType$toNMSEntityType(entity.getType()); - Key entityType = Key.of(String.valueOf(entity.getType())); - if (EntityUtils.isPetOwner(player, entity)) return true; - if (EntityUtils.isPiglinWithGoldIngot(entity, item)) return true; - if (!player.isSneaking()) { - if (EntityUtils.isHappyGhastRideable(entity)) return true; - if (entity instanceof Boat) return true; - if (entity instanceof RideableMinecart) return true; - if (entity instanceof Steerable steerable && steerable.hasSaddle()) return true; - } - return entity instanceof ChestBoat || INTERACTABLE_ENTITIES.contains(entityType); + public static boolean isEntityInteractable(Player player, Entity entity, @Nullable Item item) { + Key key = Key.of(String.valueOf(entity.getType())); + TriFunction, Boolean> func = ENTITY_INTERACTIONS.get(key); + return func != null && func.apply(player, entity, item); } public static boolean willConsume(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java index 4b34d4c20..8691c0912 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java @@ -19,16 +19,43 @@ public class EntityKeys { public static final Key ITEM_FRAME = Key.of("minecraft:ITEM_FRAME"); public static final Key GLOW_ITEM_FRAME = Key.of("minecraft:GLOW_ITEM_FRAME"); public static final Key INTERACTION = Key.of("minecraft:INTERACTION"); - // ≥1.20.5 + + public static final Key ACACIA_BOAT = Key.of("minecraft:ACACIA_BOAT"); + public static final Key BAMBOO_BOAT = Key.of("minecraft:BAMBOO_BOAT"); + public static final Key BIRCH_BOAT = Key.of("minecraft:BIRCH_BOAT"); + public static final Key CHERRY_BOAT = Key.of("minecraft:CHERRY_BOAT"); + public static final Key DARK_OAK_BOAT = Key.of("minecraft:DARK_OAK_BOAT"); + public static final Key JUNGLE_BOAT = Key.of("minecraft:JUNGLE_BOAT"); + public static final Key MANGROVE_BOAT = Key.of("minecraft:MANGROVE_BOAT"); + public static final Key OAK_BOAT = Key.of("minecraft:OAK_BOAT"); + public static final Key SPRUCE_BOAT = Key.of("minecraft:SPRUCE_BOAT"); + public static final Key MINECART = Key.of("minecraft:MINECART"); + + public static final Key ACACIA_CHEST_BOAT = Key.of("minecraft:ACACIA_CHEST_BOAT"); + public static final Key BAMBOO_CHEST_BOAT = Key.of("minecraft:BAMBOO_CHEST_BOAT"); + public static final Key BIRCH_CHEST_BOAT = Key.of("minecraft:BIRCH_CHEST_BOAT"); + public static final Key CHERRY_CHEST_BOAT = Key.of("minecraft:CHERRY_CHEST_BOAT"); + public static final Key DARK_OAK_CHEST_BOAT = Key.of("minecraft:DARK_OAK_CHEST_BOAT"); + public static final Key JUNGLE_CHEST_BOAT = Key.of("minecraft:JUNGLE_CHEST_BOAT"); + public static final Key MANGROVE_CHEST_BOAT = Key.of("minecraft:MANGROVE_CHEST_BOAT"); + public static final Key OAK_CHEST_BOAT = Key.of("minecraft:OAK_CHEST_BOAT"); + public static final Key SPRUCE_CHEST_BOAT = Key.of("minecraft:SPRUCE_CHEST_BOAT"); public static final Key CHEST_MINECART = Key.of("minecraft:CHEST_MINECART"); public static final Key FURNACE_MINECART = Key.of("minecraft:FURNACE_MINECART"); public static final Key HOPPER_MINECART = Key.of("minecraft:HOPPER_MINECART"); public static final Key COMMAND_BLOCK_MINECART = Key.of("minecraft:COMMAND_BLOCK_MINECART"); - // <1.20.5 + //<1.20.5 public static final Key MINECART_CHEST = Key.of("minecraft:MINECART_CHEST"); public static final Key MINECART_FURNACE = Key.of("minecraft:MINECART_FURNACE"); public static final Key MINECART_HOPPER = Key.of("minecraft:MINECART_HOPPER"); public static final Key MINECART_COMMAND = Key.of("minecraft:MINECART_COMMAND"); - // ≥1.21.6 + + public static final Key PIG = Key.of("minecraft:PIG"); + public static final Key STRIDER = Key.of("minecraft:STRIDER"); + + public static final Key WOLF = Key.of("minecraft:WOLF"); + public static final Key CAT = Key.of("minecraft:CAT"); + public static final Key PARROT = Key.of("minecraft:PARROT"); + public static final Key HAPPY_GHAST = Key.of("minecraft:HAPPY_GHAST"); } From fa9feb3b8b74bb3516307705a77f67ec5c2aaa15 Mon Sep 17 00:00:00 2001 From: halogly Date: Tue, 22 Jul 2025 18:09:48 +0800 Subject: [PATCH 33/83] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=87=91=E9=94=AD?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=EF=BC=8C=E6=B2=A1=E5=BF=85=E8=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/momirealms/craftengine/bukkit/util/EntityUtils.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index 2772f445e..a0ddb917c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -46,12 +46,6 @@ public class EntityUtils { && tameable.getOwnerUniqueId() == player.getUniqueId(); } - public static boolean isPiglinWithGoldIngot(Entity entity, Item item) { - return entity.getType() == EntityType.PIGLIN && - item != null && - item.vanillaId().equals(Key.of("minecraft:gold_ingot")); - } - public static boolean isHappyGhastRideable(Entity entity) { if (!VersionHelper.isOrAbove1_21_6()) return false; if (entity instanceof LivingEntity living && entity.getType() == EntityType.HAPPY_GHAST) { From 9f38dd49c6111cc7b1cb3bb5ef16837f7ca72c0d Mon Sep 17 00:00:00 2001 From: halogly Date: Tue, 22 Jul 2025 18:11:52 +0800 Subject: [PATCH 34/83] =?UTF-8?q?=E5=87=8F=E5=B0=91=E5=AE=A0=E7=89=A9?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/momirealms/craftengine/bukkit/util/EntityUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index a0ddb917c..5d820708d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -40,8 +40,7 @@ public class EntityUtils { } public static boolean isPetOwner(Player player, Entity entity) { - if (!(entity instanceof Sittable sittable)) return false; - return sittable instanceof Tameable tameable + return entity instanceof Tameable tameable && tameable.isTamed() && tameable.getOwnerUniqueId() == player.getUniqueId(); } From 86c014b252e37362d93f37dce1105d50d96cecef Mon Sep 17 00:00:00 2001 From: halogly Date: Tue, 22 Jul 2025 19:24:22 +0800 Subject: [PATCH 35/83] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E5=BA=94=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/util/EntityUtils.java | 21 ------ .../bukkit/util/InteractUtils.java | 66 ++++++++++--------- 2 files changed, 36 insertions(+), 51 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index 5d820708d..e7fe96bb1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -1,18 +1,13 @@ package net.momirealms.craftengine.bukkit.util; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.util.Key; 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.event.entity.CreatureSpawnEvent; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.ItemStack; import java.util.function.Consumer; @@ -38,20 +33,4 @@ public class EntityUtils { return LegacyEntityUtils.spawnEntity(world, loc, type, function); } } - - public static boolean isPetOwner(Player player, Entity entity) { - return entity instanceof Tameable tameable - && tameable.isTamed() - && tameable.getOwnerUniqueId() == player.getUniqueId(); - } - - public static boolean isHappyGhastRideable(Entity entity) { - if (!VersionHelper.isOrAbove1_21_6()) return false; - if (entity instanceof LivingEntity living && entity.getType() == EntityType.HAPPY_GHAST) { - ItemStack bodyItem = living.getEquipment().getItem(EquipmentSlot.BODY); - Item wrapped = BukkitItemManager.instance().wrap(bodyItem); - return wrapped.is(Key.of("harnesses")); - } - return false; - } } \ No newline at end of file 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 ea50ffd26..0f93adcd7 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 @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.block.BlockKeys; import net.momirealms.craftengine.core.entity.EntityKeys; import net.momirealms.craftengine.core.item.Item; @@ -11,16 +11,14 @@ 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 org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bell; import org.bukkit.block.data.type.ChiseledBookshelf; import org.bukkit.entity.*; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; @@ -285,7 +283,31 @@ public class InteractUtils { } static { - // 忽视潜行的交互实体 + // 有鞍 + 非潜行可交互(如猪、炽足兽) + registerEntityInteraction(EntityKeys.PIG, (player, entity, item) -> hasSaddle(player, entity) && !player.isSneaking()); + registerEntityInteraction(EntityKeys.STRIDER, (player, entity, item) -> hasSaddle(player, entity) && !player.isSneaking()); + registerEntityInteraction(EntityKeys.WOLF, (player, entity, item) -> isPetOwner(player, entity)); + registerEntityInteraction(EntityKeys.CAT, (player, entity, item) -> isPetOwner(player, entity)); + registerEntityInteraction(EntityKeys.PARROT, (player, entity, item) -> isPetOwner(player, entity)); + registerEntityInteraction(EntityKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.BAMBOO_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.CHERRY_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.DARK_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.JUNGLE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.MANGROVE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.SPRUCE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.MINECART, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.HAPPY_GHAST, (player, entity, item) -> { + if (!VersionHelper.isOrAbove1_21_6()) return false; + if (entity instanceof LivingEntity living && entity.getType() == EntityType.HAPPY_GHAST) { + ItemStack bodyItem = living.getEquipment().getItem(EquipmentSlot.BODY); + Item wrapped = BukkitItemManager.instance().wrap(bodyItem); + return wrapped.is(Key.of("harnesses")); + } + return false; + }); registerEntityInteraction(EntityKeys.ALLAY, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.HORSE, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.ZOMBIE_HORSE, (player, entity, item) -> true); @@ -300,18 +322,6 @@ public class InteractUtils { registerEntityInteraction(EntityKeys.ITEM_FRAME, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.GLOW_ITEM_FRAME, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.INTERACTION, (player, entity, item) -> true); - // 潜行时不可交互 - registerEntityInteraction(EntityKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.BAMBOO_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.CHERRY_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.DARK_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.JUNGLE_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.MANGROVE_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.OAK_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.SPRUCE_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.MINECART, (player, entity, item) -> !player.isSneaking()); - // 始终可交互的箱子类船车 registerEntityInteraction(EntityKeys.ACACIA_CHEST_BOAT, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.BAMBOO_CHEST_BOAT, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.BIRCH_CHEST_BOAT, (player, entity, item) -> true); @@ -330,18 +340,6 @@ public class InteractUtils { registerEntityInteraction(EntityKeys.MINECART_HOPPER, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.MINECART_FURNACE, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.MINECART_COMMAND, (player, entity, item) -> true); - // 有鞍 + 非潜行可交互(如猪、炽足兽) - registerEntityInteraction(EntityKeys.PIG, (player, entity, item) -> - entity instanceof Steerable steerable && steerable.hasSaddle() && !player.isSneaking()); - registerEntityInteraction(EntityKeys.STRIDER, (player, entity, item) -> - entity instanceof Steerable steerable && steerable.hasSaddle() && !player.isSneaking()); - // 是宠物,且主人是玩家(忽视潜行) - registerEntityInteraction(EntityKeys.WOLF, (player, entity, item) -> EntityUtils.isPetOwner(player, entity)); - registerEntityInteraction(EntityKeys.CAT, (player, entity, item) -> EntityUtils.isPetOwner(player, entity)); - registerEntityInteraction(EntityKeys.PARROT, (player, entity, item) -> EntityUtils.isPetOwner(player, entity)); - // 快乐恶魂(装备挽具、受潜行影响) - registerEntityInteraction(EntityKeys.HAPPY_GHAST, (player, entity, item) -> - EntityUtils.isHappyGhastRideable(entity) && !player.isSneaking()); } private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { @@ -393,4 +391,12 @@ public class InteractUtils { private static boolean canEat(Player player, boolean ignoreHunger) { return ignoreHunger || player.isInvulnerable() || player.getFoodLevel() < 20; } + + public static boolean hasSaddle(Player player, Entity entity) { + return entity instanceof Steerable steerable && steerable.hasSaddle() && !player.isSneaking(); + } + + public static boolean isPetOwner(Player player, Entity entity) { + return entity instanceof Tameable tameable && tameable.isTamed() && tameable.getOwnerUniqueId() == player.getUniqueId(); + } } From c2e34ec965d471ea427f415f5ff2fe42d78dd7b9 Mon Sep 17 00:00:00 2001 From: halogly Date: Wed, 23 Jul 2025 00:04:23 +0800 Subject: [PATCH 36/83] =?UTF-8?q?=E5=B0=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/InteractUtils.java | 10 ++--- .../craftengine/core/entity/EntityKeys.java | 38 +++++++++---------- .../craftengine/core/item/ItemKeys.java | 1 + 3 files changed, 23 insertions(+), 26 deletions(-) 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 0f93adcd7..2809910b7 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 @@ -27,8 +27,8 @@ import java.util.*; public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); private static final Map, BlockData, BlockHitResult, Boolean>> WILL_CONSUME = new HashMap<>(); - private static final Key NOTE_BLOCK_TOP_INSTRUMENTS = Key.of("minecraft:noteblock_top_instruments"); private static final Map, Boolean>> ENTITY_INTERACTIONS = new HashMap<>(); + private static final Key NOTE_BLOCK_TOP_INSTRUMENTS = Key.of("minecraft:noteblock_top_instruments"); private InteractUtils() {} @@ -283,7 +283,7 @@ public class InteractUtils { } static { - // 有鞍 + 非潜行可交互(如猪、炽足兽) + registerEntityInteraction(EntityKeys.PIGLIN, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.GOLD_INGOT)); registerEntityInteraction(EntityKeys.PIG, (player, entity, item) -> hasSaddle(player, entity) && !player.isSneaking()); registerEntityInteraction(EntityKeys.STRIDER, (player, entity, item) -> hasSaddle(player, entity) && !player.isSneaking()); registerEntityInteraction(EntityKeys.WOLF, (player, entity, item) -> isPetOwner(player, entity)); @@ -301,8 +301,8 @@ public class InteractUtils { registerEntityInteraction(EntityKeys.MINECART, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityKeys.HAPPY_GHAST, (player, entity, item) -> { if (!VersionHelper.isOrAbove1_21_6()) return false; - if (entity instanceof LivingEntity living && entity.getType() == EntityType.HAPPY_GHAST) { - ItemStack bodyItem = living.getEquipment().getItem(EquipmentSlot.BODY); + if (entity instanceof HappyGhast happyGhast) { + ItemStack bodyItem = happyGhast.getEquipment().getItem(EquipmentSlot.BODY); Item wrapped = BukkitItemManager.instance().wrap(bodyItem); return wrapped.is(Key.of("harnesses")); } @@ -397,6 +397,6 @@ public class InteractUtils { } public static boolean isPetOwner(Player player, Entity entity) { - return entity instanceof Tameable tameable && tameable.isTamed() && tameable.getOwnerUniqueId() == player.getUniqueId(); + return entity instanceof Tameable tameable && tameable.isTamed() && player.getUniqueId().equals(tameable.getOwnerUniqueId()); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java index 8691c0912..6f075e3d6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java @@ -5,6 +5,23 @@ import net.momirealms.craftengine.core.util.Key; public class EntityKeys { private EntityKeys() {} + public static final Key PIG = Key.of("minecraft:PIG"); + public static final Key STRIDER = Key.of("minecraft:STRIDER"); + public static final Key WOLF = Key.of("minecraft:WOLF"); + public static final Key CAT = Key.of("minecraft:CAT"); + public static final Key PARROT = Key.of("minecraft:PARROT"); + public static final Key ACACIA_BOAT = Key.of("minecraft:ACACIA_BOAT"); + public static final Key BAMBOO_BOAT = Key.of("minecraft:BAMBOO_BOAT"); + public static final Key BIRCH_BOAT = Key.of("minecraft:BIRCH_BOAT"); + public static final Key CHERRY_BOAT = Key.of("minecraft:CHERRY_BOAT"); + public static final Key DARK_OAK_BOAT = Key.of("minecraft:DARK_OAK_BOAT"); + public static final Key JUNGLE_BOAT = Key.of("minecraft:JUNGLE_BOAT"); + public static final Key MANGROVE_BOAT = Key.of("minecraft:MANGROVE_BOAT"); + public static final Key OAK_BOAT = Key.of("minecraft:OAK_BOAT"); + public static final Key SPRUCE_BOAT = Key.of("minecraft:SPRUCE_BOAT"); + public static final Key MINECART = Key.of("minecraft:MINECART"); + public static final Key HAPPY_GHAST = Key.of("minecraft:HAPPY_GHAST"); + public static final Key PIGLIN = Key.of("minecraft:PIGLIN"); public static final Key ALLAY = Key.of("minecraft:ALLAY"); public static final Key HORSE = Key.of("minecraft:HORSE"); public static final Key ZOMBIE_HORSE = Key.of("minecraft:ZOMBIE_HORSE"); @@ -19,18 +36,6 @@ public class EntityKeys { public static final Key ITEM_FRAME = Key.of("minecraft:ITEM_FRAME"); public static final Key GLOW_ITEM_FRAME = Key.of("minecraft:GLOW_ITEM_FRAME"); public static final Key INTERACTION = Key.of("minecraft:INTERACTION"); - - public static final Key ACACIA_BOAT = Key.of("minecraft:ACACIA_BOAT"); - public static final Key BAMBOO_BOAT = Key.of("minecraft:BAMBOO_BOAT"); - public static final Key BIRCH_BOAT = Key.of("minecraft:BIRCH_BOAT"); - public static final Key CHERRY_BOAT = Key.of("minecraft:CHERRY_BOAT"); - public static final Key DARK_OAK_BOAT = Key.of("minecraft:DARK_OAK_BOAT"); - public static final Key JUNGLE_BOAT = Key.of("minecraft:JUNGLE_BOAT"); - public static final Key MANGROVE_BOAT = Key.of("minecraft:MANGROVE_BOAT"); - public static final Key OAK_BOAT = Key.of("minecraft:OAK_BOAT"); - public static final Key SPRUCE_BOAT = Key.of("minecraft:SPRUCE_BOAT"); - public static final Key MINECART = Key.of("minecraft:MINECART"); - public static final Key ACACIA_CHEST_BOAT = Key.of("minecraft:ACACIA_CHEST_BOAT"); public static final Key BAMBOO_CHEST_BOAT = Key.of("minecraft:BAMBOO_CHEST_BOAT"); public static final Key BIRCH_CHEST_BOAT = Key.of("minecraft:BIRCH_CHEST_BOAT"); @@ -49,13 +54,4 @@ public class EntityKeys { public static final Key MINECART_FURNACE = Key.of("minecraft:MINECART_FURNACE"); public static final Key MINECART_HOPPER = Key.of("minecraft:MINECART_HOPPER"); public static final Key MINECART_COMMAND = Key.of("minecraft:MINECART_COMMAND"); - - public static final Key PIG = Key.of("minecraft:PIG"); - public static final Key STRIDER = Key.of("minecraft:STRIDER"); - - public static final Key WOLF = Key.of("minecraft:WOLF"); - public static final Key CAT = Key.of("minecraft:CAT"); - public static final Key PARROT = Key.of("minecraft:PARROT"); - - public static final Key HAPPY_GHAST = Key.of("minecraft:HAPPY_GHAST"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 89916d9e3..7fc6b799a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -33,6 +33,7 @@ public class ItemKeys { public static final Key BARRIER = Key.of("minecraft:barrier"); public static final Key CACTUS = Key.of("minecraft:cactus"); public static final Key REDSTONE = Key.of("minecraft:redstone"); + public static final Key GOLD_INGOT = Key.of("minecraft:gold_ingot"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE From 59b29b94944e63bbaceab15705c95f1eea45dc17 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 23 Jul 2025 17:44:44 +0800 Subject: [PATCH 37/83] =?UTF-8?q?=E5=90=88=E5=B9=B6=E8=AF=AD=E8=A8=80lang?= =?UTF-8?q?=20json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/modifier/HideTooltipModifier.java | 2 +- .../core/pack/AbstractPackManager.java | 21 +++++++++++++++---- .../core/plugin/config/Config.java | 9 ++++---- .../craftengine/core/util/VersionHelper.java | 1 + gradle.properties | 2 +- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java index 4b56b6b74..56fa6eea9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java @@ -88,7 +88,7 @@ public class HideTooltipModifier implements ItemDataModifier { } public List components() { - return components; + return this.components; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 395f6af8e..7f7a20441 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -667,6 +667,10 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().info("Validated resource pack in " + (time3 - time2) + "ms"); Path finalPath = resourcePackPath(); Files.createDirectories(finalPath.getParent()); + if (!VersionHelper.PREMIUM) { + Config.instance().setObf(false); + this.plugin.logger().warn("Resource pack obfuscation requires Premium Edition."); + } try { this.zipGenerator.accept(generatedPackPath, finalPath); } catch (Exception e) { @@ -1551,15 +1555,24 @@ public abstract class AbstractPackManager implements PackManager { private void generateClientLang(Path generatedPackPath) { for (Map.Entry entry : this.plugin.translationManager().clientLangData().entrySet()) { - JsonObject json = new JsonObject(); - for (Map.Entry pair : entry.getValue().translations.entrySet()) { - json.addProperty(pair.getKey(), pair.getValue()); - } Path langPath = generatedPackPath .resolve("assets") .resolve("minecraft") .resolve("lang") .resolve(entry.getKey() + ".json"); + JsonObject json; + if (Files.exists(langPath)) { + try { + json = GsonHelper.readJsonFile(langPath).getAsJsonObject(); + } catch (Exception e) { + json = new JsonObject(); + } + } else { + json = new JsonObject(); + } + for (Map.Entry pair : entry.getValue().translations.entrySet()) { + json.addProperty(pair.getKey(), pair.getValue()); + } try { Files.createDirectories(langPath.getParent()); } catch (IOException e) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 425de32f9..04f031e4e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -20,10 +20,7 @@ import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MinecraftVersion; -import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.InjectionTarget; import net.momirealms.craftengine.core.world.chunk.storage.CompressionMethod; @@ -832,6 +829,10 @@ public class Config { return instance.recipe$ingredient_sources; } + public void setObf(boolean enable) { + this.resource_pack$protection$obfuscation$enable = enable; + } + public YamlDocument loadOrCreateYamlData(String fileName) { Path path = this.plugin.dataFolderPath().resolve(fileName); if (!Files.exists(path)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java index 12e001c79..3890ad838 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java @@ -7,6 +7,7 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; public class VersionHelper { + public static final boolean PREMIUM = true; public static final MinecraftVersion MINECRAFT_VERSION; private static final int version; private static final int majorVersion; diff --git a/gradle.properties b/gradle.properties index 2c126627e..fd7531d70 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,7 +40,7 @@ commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 commons_lang3_version=3.17.0 sparrow_nbt_version=0.9.4 -sparrow_util_version=0.50.6 +sparrow_util_version=0.50.7 fastutil_version=8.5.15 netty_version=4.1.121.Final joml_version=1.10.8 From e5c01c55cf6800da5a645703cb6522a9aed324c3 Mon Sep 17 00:00:00 2001 From: iqtester Date: Wed, 23 Jul 2025 12:49:38 -0400 Subject: [PATCH 38/83] Add DoubleHighBlockItemBehavior --- .../item/behavior/BlockItemBehavior.java | 6 +- .../item/behavior/BukkitItemBehaviors.java | 2 + .../behavior/DoubleHighBlockItemBehavior.java | 62 +++++++++++++++++++ .../plugin/reflection/minecraft/MBlocks.java | 4 ++ .../default/configuration/palm_tree.yml | 2 +- .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 1 + 7 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index affec07c6..0fda1036a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -126,7 +126,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { // it's just world + pos BlockState previousState = bukkitBlock.getState(); // place custom block - CraftEngineBlocks.place(placeLocation, blockStateToPlace, UpdateOption.UPDATE_ALL_IMMEDIATE, false); + placeBlock(placeLocation, blockStateToPlace); if (player != null) { // call bukkit event @@ -215,6 +215,10 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { } } + protected boolean placeBlock(Location location, ImmutableBlockState blockState) { + return CraftEngineBlocks.place(location, blockState, UpdateOption.UPDATE_ALL_IMMEDIATE, false); + } + @Override public Key block() { return this.blockId; 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 51a030ce8..79292cfda 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 @@ -11,6 +11,7 @@ public class BukkitItemBehaviors extends ItemBehaviors { public static final Key FLINT_AND_STEEL_ITEM = Key.from("craftengine:flint_and_steel_item"); 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 void init() { register(EMPTY, EmptyItemBehavior.FACTORY); @@ -20,5 +21,6 @@ public class BukkitItemBehaviors extends ItemBehaviors { register(FLINT_AND_STEEL_ITEM, FlintAndSteelItemBehavior.FACTORY); register(COMPOSTABLE_ITEM, CompostableItemBehavior.FACTORY); register(AXE_ITEM, AxeItemBehavior.FACTORY); + register(DOUBLE_HIGH_BLOCK_ITEM, DoubleHighBlockItemBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java new file mode 100644 index 000000000..d89aecabb --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -0,0 +1,62 @@ +package net.momirealms.craftengine.bukkit.item.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import org.bukkit.Location; +import org.bukkit.Material; + +import java.nio.file.Path; +import java.util.Map; + +public class DoubleHighBlockItemBehavior extends BlockItemBehavior { + public static final Factory FACTORY = new Factory(); + + public DoubleHighBlockItemBehavior(Key blockId) { + super(blockId); + } + + @Override + protected boolean placeBlock(Location location, ImmutableBlockState blockState) { + Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()); + Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()); + UpdateOption option = UpdateOption.builder().updateNeighbors().updateClients().updateImmediate().updateKnownShape().build(); + Object stateToPlace; + if (location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()).getType() == Material.WATER) { + stateToPlace = MBlocks.WATER$defaultState; + } else { + stateToPlace = MBlocks.AIR$defaultState; + } + FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, stateToPlace, option.flags()); + return super.placeBlock(location, blockState); + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + Object id = arguments.get("block"); + if (id == null) { + throw new LocalizedResourceConfigException("warning.config.item.behavior.double_high.missing_block", new IllegalArgumentException("Missing required parameter 'block' for double_high_block_item behavior")); + } + if (id instanceof Map map) { + if (map.containsKey(key.toString())) { + // 防呆 + BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + } else { + BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + } + return new DoubleHighBlockItemBehavior(key); + } else { + return new DoubleHighBlockItemBehavior(Key.of(id.toString())); + } + } + } +} 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 34d2f0e65..5255de607 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 @@ -18,6 +18,8 @@ public final class MBlocks { public static final Object SHULKER_BOX; public static final Object COMPOSTER; public static final Object SNOW; + public static final Object WATER; + public static final Object WATER$defaultState; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -37,5 +39,7 @@ public final class MBlocks { SHULKER_BOX = getById("shulker_box"); COMPOSTER = getById("composter"); SNOW = getById("snow"); + WATER = getById("water"); + WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); } } diff --git a/common-files/src/main/resources/resources/default/configuration/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/palm_tree.yml index bd0b2d3ac..a47b29498 100644 --- a/common-files/src/main/resources/resources/default/configuration/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/palm_tree.yml @@ -348,7 +348,7 @@ items: arguments: path: minecraft:item/custom/palm_door behavior: - type: block_item + type: double_high_block_item block: behavior: type: door_block diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 375cfd1f0..3134565f4 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -187,6 +187,7 @@ warning.config.item.behavior.invalid_type: "Issue found in file warning.config.item.behavior.block.missing_block: "Issue found in file - The item '' is missing the required 'block' argument for 'block_item' behavior." warning.config.item.behavior.furniture.missing_furniture: "Issue found in file - The item '' is missing the required 'furniture' argument for 'furniture_item' behavior." warning.config.item.behavior.liquid_collision.missing_block: "Issue found in file - The item '' is missing the required 'block' argument for 'liquid_collision_block_item' behavior." +warning.config.item.behavior.double_high.missing_block: "Issue found in file - The item '' is missing the required 'block' argument for 'double_high_block_item' behavior." warning.config.item.legacy_model.missing_path: "Issue found in file - The item '' is missing the require 'path' argument for legacy-model." warning.config.item.legacy_model.overrides.missing_path: "Issue found in file - The item '' is missing the require 'path' argument for legacy-model overrides." warning.config.item.legacy_model.overrides.missing_predicate: "Issue found in file - The item '' is missing the require 'predicate' argument for legacy-model overrides." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 91bfbf70c..8832c01d1 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -185,6 +185,7 @@ warning.config.item.behavior.invalid_type: "在文件 发现问 warning.config.item.behavior.block.missing_block: "在文件 发现问题 - 物品 '' 的 'block_item' 行为缺少必需的 'block' 参数" warning.config.item.behavior.furniture.missing_furniture: "在文件 发现问题 - 物品 '' 的 'furniture_item' 行为缺少必需的 'furniture' 参数" warning.config.item.behavior.liquid_collision.missing_block: "在文件 发现问题 - 物品 '' 的 'liquid_collision_block_item' 行为缺少必需的 'block' 参数" +warning.config.item.behavior.double_high.missing_block: "在文件 发现问题 - 物品 '' 的 'double_high_block_item' 行为缺少必需的 'block' 参数" warning.config.item.legacy_model.missing_path: "在文件 中发现问题 - 物品 '' 的旧版模型(legacy-model)缺少必需的 'path' 参数" warning.config.item.legacy_model.overrides.missing_path: "在文件 中发现问题 - 物品 '' 的旧版模型覆写规则(overrides)缺少必需的 'path' 参数" warning.config.item.legacy_model.overrides.missing_predicate: "在文件 中发现问题 - 物品 '' 的旧版模型覆写规则(overrides)缺少必需的 'predicate' 参数" From 16e4f4ee886c8c62ae1c4078a122e77aa73d34f4 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 24 Jul 2025 17:36:02 +0800 Subject: [PATCH 39/83] =?UTF-8?q?=E5=91=BD=E5=90=8D=E6=9B=B4=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/BukkitBlockBehaviors.java | 4 ++-- ...oubleBlockBehavior.java => DoubleHighBlockBehavior.java} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/{DoubleBlockBehavior.java => DoubleHighBlockBehavior.java} (95%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 3f1d586b7..e4b503afb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -26,7 +26,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key SLAB_BLOCK = Key.from("craftengine:slab_block"); public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block"); public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block"); - public static final Key DOUBLE_BLOCK = Key.from("craftengine:double_block"); + public static final Key DOUBLE_HIGH_BLOCK = Key.from("craftengine:double_high_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -51,6 +51,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(SLAB_BLOCK, SlabBlockBehavior.FACTORY); register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY); register(PRESSURE_PLATE_BLOCK, PressurePlateBlockBehavior.FACTORY); - register(DOUBLE_BLOCK, DoubleBlockBehavior.FACTORY); + register(DOUBLE_HIGH_BLOCK, DoubleHighBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java similarity index 95% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleBlockBehavior.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index 089510d9e..40425df98 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -21,11 +21,11 @@ import java.util.Map; import java.util.concurrent.Callable; -public class DoubleBlockBehavior extends BukkitBlockBehavior { +public class DoubleHighBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property halfProperty; - public DoubleBlockBehavior(CustomBlock customBlock, Property halfProperty) { + public DoubleHighBlockBehavior(CustomBlock customBlock, Property halfProperty) { super(customBlock); this.halfProperty = halfProperty; } @@ -84,7 +84,7 @@ public class DoubleBlockBehavior extends BukkitBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { Property half = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.double.missing_half"); - return new DoubleBlockBehavior(block, half); + return new DoubleHighBlockBehavior(block, half); } } } From bb3c11016c2dfde38dd353668ad271924c2f198d Mon Sep 17 00:00:00 2001 From: halogly Date: Thu, 24 Jul 2025 17:51:04 +0800 Subject: [PATCH 40/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E4=BA=A4=E4=BA=92=EF=BC=8C=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=8F=AF=E4=BA=A4=E4=BA=92=E6=96=B9=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/InteractUtils.java | 92 +++++++++++++++---- .../craftengine/core/block/BlockKeys.java | 14 +++ .../craftengine/core/entity/EntityKeys.java | 24 +++++ .../craftengine/core/item/ItemKeys.java | 5 + 4 files changed, 119 insertions(+), 16 deletions(-) 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 2809910b7..39cbba3da 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 @@ -1,5 +1,6 @@ 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.recipe.BukkitRecipeManager; import net.momirealms.craftengine.core.block.BlockKeys; @@ -52,6 +53,9 @@ public class InteractUtils { registerInteraction(BlockKeys.GREEN_CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); registerInteraction(BlockKeys.RED_CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); registerInteraction(BlockKeys.BLACK_CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); + registerInteraction(BlockKeys.BEE_NEST, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.SHEARS) || item.vanillaId().equals(ItemKeys.GLASS_BOTTLE)); + registerInteraction(BlockKeys.BEEHIVE, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.SHEARS) || item.vanillaId().equals(ItemKeys.GLASS_BOTTLE)); + registerInteraction(BlockKeys.POWDER_SNOW, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.BUCKET)); registerInteraction(BlockKeys.BELL, (player, item, blockState, result) -> { Direction direction = result.getDirection(); BlockPos pos = result.getBlockPos(); @@ -270,9 +274,14 @@ public class InteractUtils { registerInteraction(BlockKeys.RED_BED, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.BLACK_BED, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DRAGON_EGG, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.REPEATING_COMMAND_BLOCK, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.CHAIN_COMMAND_BLOCK, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.COMMAND_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.CHAIN_COMMAND_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.REPEATING_COMMAND_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.JIGSAW, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.STRUCTURE_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.TEST_INSTANCE_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.TEST_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.LIGHT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.REDSTONE_ORE, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DEEPSLATE_REDSTONE_ORE, (player, item, blockState, result) -> true); } @@ -283,12 +292,53 @@ public class InteractUtils { } static { - registerEntityInteraction(EntityKeys.PIGLIN, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.GOLD_INGOT)); - registerEntityInteraction(EntityKeys.PIG, (player, entity, item) -> hasSaddle(player, entity) && !player.isSneaking()); - registerEntityInteraction(EntityKeys.STRIDER, (player, entity, item) -> hasSaddle(player, entity) && !player.isSneaking()); - registerEntityInteraction(EntityKeys.WOLF, (player, entity, item) -> isPetOwner(player, entity)); - registerEntityInteraction(EntityKeys.CAT, (player, entity, item) -> isPetOwner(player, entity)); - registerEntityInteraction(EntityKeys.PARROT, (player, entity, item) -> isPetOwner(player, entity)); + registerEntityInteraction(EntityKeys.BEE, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.FOX, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.FROG, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.PANDA, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.HOGLIN, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.OCELOT, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.RABBIT, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.TURTLE, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.CHICKEN, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.SNIFFER, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityKeys.AXOLOTL, (player, entity, item) -> + canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET))); + registerEntityInteraction(EntityKeys.COD, (player, entity, item) -> + item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); + registerEntityInteraction(EntityKeys.SALMON, (player, entity, item) -> + item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); + registerEntityInteraction(EntityKeys.TROPICAL_FISH, (player, entity, item) -> + item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); + registerEntityInteraction(EntityKeys.PUFFERFISH, (player, entity, item) -> + item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); + registerEntityInteraction(EntityKeys.TADPOLE, (player, entity, item) -> + item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); + registerEntityInteraction(EntityKeys.SNOW_GOLEM, (player, entity, item) -> shearable(entity, item)); + registerEntityInteraction(EntityKeys.SHEEP, (player, entity, item) -> canFeed(entity, item) || shearable(entity, item)); + registerEntityInteraction(EntityKeys.BOGGED, (player, entity, item) -> canFeed(entity, item) || shearable(entity, item)); + registerEntityInteraction(EntityKeys.MOOSHROOM, (player, entity, item) -> + canFeed(entity, item) || shearable(entity, item) || (item != null && (item.vanillaId().equals(ItemKeys.BUCKET) || item.vanillaId().equals(ItemKeys.BOWL)))); + registerEntityInteraction(EntityKeys.COW, (player, entity, item) -> + canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.BUCKET))); + registerEntityInteraction(EntityKeys.GOAT, (player, entity, item) -> + canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.BUCKET))); + registerEntityInteraction(EntityKeys.CREEPER, (player, entity, item) -> + item != null && item.vanillaId().equals(ItemKeys.FLINT_AND_STEEL)); + registerEntityInteraction(EntityKeys.PIGLIN, (player, entity, item) -> + item != null && item.vanillaId().equals(ItemKeys.GOLD_INGOT)); + registerEntityInteraction(EntityKeys.ARMADILLO, (player, entity, item) -> + canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.BRUSH))); + registerEntityInteraction(EntityKeys.ZOMBIE_HORSE, (player, entity, item) -> + entity instanceof Tameable tameable && tameable.isTamed()); + registerEntityInteraction(EntityKeys.SKELETON_HORSE, (player, entity, item) -> + entity instanceof Tameable tameable && tameable.isTamed()); + registerEntityInteraction(EntityKeys.PIG, (player, entity, item) -> + canFeed(entity, item) || (hasSaddle(player, entity) && !player.isSneaking())); + registerEntityInteraction(EntityKeys.STRIDER, (player, entity, item) -> + canFeed(entity, item) || (hasSaddle(player, entity) && !player.isSneaking())); + registerEntityInteraction(EntityKeys.WOLF, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); + registerEntityInteraction(EntityKeys.CAT, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); registerEntityInteraction(EntityKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityKeys.BAMBOO_BOAT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); @@ -299,19 +349,21 @@ public class InteractUtils { registerEntityInteraction(EntityKeys.OAK_BOAT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityKeys.SPRUCE_BOAT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityKeys.MINECART, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityKeys.PARROT, (player, entity, item) -> { + if (item != null && item.is(Key.of("parrot_poisonous_food"))) return true; + return canFeed(entity, item) || isPetOwner(player, entity); + }); registerEntityInteraction(EntityKeys.HAPPY_GHAST, (player, entity, item) -> { if (!VersionHelper.isOrAbove1_21_6()) return false; - if (entity instanceof HappyGhast happyGhast) { + if (entity instanceof HappyGhast happyGhast && !player.isSneaking()) { ItemStack bodyItem = happyGhast.getEquipment().getItem(EquipmentSlot.BODY); - Item wrapped = BukkitItemManager.instance().wrap(bodyItem); - return wrapped.is(Key.of("harnesses")); + Item wrap = BukkitItemManager.instance().wrap(bodyItem); + return wrap.is(Key.of("harnesses")); } - return false; + return canFeed(entity, item); }); registerEntityInteraction(EntityKeys.ALLAY, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.HORSE, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.ZOMBIE_HORSE, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.SKELETON_HORSE, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.DONKEY, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.MULE, (player, entity, item) -> true); registerEntityInteraction(EntityKeys.VILLAGER, (player, entity, item) -> true); @@ -392,11 +444,19 @@ public class InteractUtils { return ignoreHunger || player.isInvulnerable() || player.getFoodLevel() < 20; } - public static boolean hasSaddle(Player player, Entity entity) { + private static boolean canFeed(Entity entity, Item item) { + return entity instanceof Animals animals && item.is(Key.of(animals.getType().toString().toLowerCase() + "_food")); + } + + private static boolean hasSaddle(Player player, Entity entity) { return entity instanceof Steerable steerable && steerable.hasSaddle() && !player.isSneaking(); } - public static boolean isPetOwner(Player player, Entity entity) { + private static boolean shearable(Entity entity, Item item) { + return entity instanceof Shearable shearable && item.vanillaId().equals(ItemKeys.SHEARS) && shearable.readyToBeSheared(); + } + + private static boolean isPetOwner(Player player, Entity entity) { return entity instanceof Tameable tameable && tameable.isTamed() && player.getUniqueId().equals(tameable.getOwnerUniqueId()); } } 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 4e377f7d2..9da2f4f3f 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 @@ -41,10 +41,22 @@ public final class BlockKeys { public static final Key COMMAND_BLOCK = Key.of("minecraft:command_block"); public static final Key CHAIN_COMMAND_BLOCK = Key.of("minecraft:chain_command_block"); public static final Key REPEATING_COMMAND_BLOCK = Key.of("minecraft:repeating_command_block"); + public static final Key JIGSAW = Key.of("minecraft:jigsaw"); + public static final Key STRUCTURE_BLOCK = Key.of("minecraft:structure_block"); + 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 DECORATED_POT = Key.of("minecraft:decorated_pot"); public static final Key CHISELED_BOOKSHELF = Key.of("minecraft:chiseled_bookshelf"); 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 BEE_NEST = Key.of("minecraft:bee_nest"); + public static final Key BEEHIVE = Key.of("minecraft:beehive"); + public static final Key POWDER_SNOW = Key.of("minecraft:powder_snow"); + public static final Key COMPOSTER = Key.of("minecraft:composter"); + public static final Key CAULDRON = Key.of("minecraft:cauldron"); + public static final Key WATER_CAULDRON = Key.of("minecraft:water_cauldron"); + public static final Key LAVA_CAULDRON = Key.of("minecraft:lava_cauldron"); public static final Key CAKE = Key.of("minecraft:cake"); public static final Key CANDLE_CAKE = Key.of("minecraft:candle_cake"); @@ -161,6 +173,8 @@ public final class BlockKeys { public static final Key WAXED_OXIDIZED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_oxidized_copper_trapdoor"); public static final Key WAXED_WEATHERED_COPPER_TRAPDOOR = Key.of("minecraft:waxed_weathered_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"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java index 6f075e3d6..721302092 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java @@ -5,6 +5,29 @@ import net.momirealms.craftengine.core.util.Key; public class EntityKeys { private EntityKeys() {} + public static final Key BEE = Key.of("minecraft:BEE"); + public static final Key FOX = Key.of("minecraft:FOX"); + public static final Key FROG = Key.of("minecraft:FROG"); + public static final Key PANDA = Key.of("minecraft:PANDA"); + public static final Key SHEEP = Key.of("minecraft:SHEEP"); + public static final Key BOGGED = Key.of("minecraft:BOGGED"); + public static final Key SNOW_GOLEM = Key.of("minecraft:SNOW_GOLEM"); + public static final Key HOGLIN = Key.of("minecraft:HOGLIN"); + public static final Key OCELOT = Key.of("minecraft:OCELOT"); + public static final Key RABBIT = Key.of("minecraft:RABBIT"); + public static final Key TURTLE = Key.of("minecraft:TURTLE"); + public static final Key AXOLOTL = Key.of("minecraft:AXOLOTL"); + public static final Key CHICKEN = Key.of("minecraft:CHICKEN"); + public static final Key SNIFFER = Key.of("minecraft:SNIFFER"); + public static final Key ARMADILLO = Key.of("minecraft:ARMADILLO"); + public static final Key COD = Key.of("minecraft:COD"); + public static final Key SALMON = Key.of("minecraft:SALMON"); + public static final Key TROPICAL_FISH = Key.of("minecraft:TROPICAL_FISH"); + public static final Key PUFFERFISH = Key.of("minecraft:PUFFERFISH"); + public static final Key TADPOLE = Key.of("minecraft:TADPOLE"); + public static final Key COW = Key.of("minecraft:COW"); + public static final Key MOOSHROOM = Key.of("minecraft:MOOSHROOM"); + public static final Key GOAT = Key.of("minecraft:GOAT"); public static final Key PIG = Key.of("minecraft:PIG"); public static final Key STRIDER = Key.of("minecraft:STRIDER"); public static final Key WOLF = Key.of("minecraft:WOLF"); @@ -22,6 +45,7 @@ public class EntityKeys { public static final Key MINECART = Key.of("minecraft:MINECART"); public static final Key HAPPY_GHAST = Key.of("minecraft:HAPPY_GHAST"); public static final Key PIGLIN = Key.of("minecraft:PIGLIN"); + public static final Key CREEPER = Key.of("minecraft:CREEPER"); public static final Key ALLAY = Key.of("minecraft:ALLAY"); public static final Key HORSE = Key.of("minecraft:HORSE"); public static final Key ZOMBIE_HORSE = Key.of("minecraft:ZOMBIE_HORSE"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 7fc6b799a..148b73bb3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -26,6 +26,7 @@ public class ItemKeys { public static final Key TROPICAL_FISH_BUCKET = Key.of("minecraft:tropical_fish_bucket"); public static final Key PUFFERFISH_BUCKET = Key.of("minecraft:pufferfish_bucket"); public static final Key AXOLOTL_BUCKET = Key.of("minecraft:axolotl_bucket"); + public static final Key LAVA_BUCKET = Key.of("minecraft:lava_bucket"); public static final Key BUCKET = Key.of("minecraft:bucket"); public static final Key BONE_MEAL = Key.of("minecraft:bone_meal"); public static final Key ENCHANTED_BOOK = Key.of("minecraft:enchanted_book"); @@ -34,6 +35,10 @@ public class ItemKeys { public static final Key CACTUS = Key.of("minecraft:cactus"); public static final Key REDSTONE = Key.of("minecraft:redstone"); public static final Key GOLD_INGOT = Key.of("minecraft:gold_ingot"); + public static final Key SHEARS = Key.of("minecraft:shears"); + public static final Key BRUSH = Key.of("minecraft:brush"); + public static final Key BOWL = Key.of("minecraft:bowl"); + public static final Key GLASS_BOTTLE = Key.of("minecraft:glass_bottle"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE From 71d3cfe1f679d5890acd9da694f08598b5b23c32 Mon Sep 17 00:00:00 2001 From: iqtester Date: Thu, 24 Jul 2025 10:44:32 -0400 Subject: [PATCH 41/83] check fluid through NMS --- .../item/behavior/DoubleHighBlockItemBehavior.java | 14 +++++--------- .../plugin/reflection/minecraft/MBlocks.java | 4 ---- .../plugin/reflection/minecraft/MFluids.java | 2 ++ 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index d89aecabb..fc8c6cb8c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.item.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; @@ -12,7 +13,6 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.bukkit.Location; -import org.bukkit.Material; import java.nio.file.Path; import java.util.Map; @@ -26,16 +26,12 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { @Override protected boolean placeBlock(Location location, ImmutableBlockState blockState) { - Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()); + Object level = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()); Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()); UpdateOption option = UpdateOption.builder().updateNeighbors().updateClients().updateImmediate().updateKnownShape().build(); - Object stateToPlace; - if (location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()).getType() == Material.WATER) { - stateToPlace = MBlocks.WATER$defaultState; - } else { - stateToPlace = MBlocks.AIR$defaultState; - } - FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, stateToPlace, option.flags()); + Object fluidData = FastNMS.INSTANCE.method$BlockGetter$getFluidState(level, blockPos); + Object stateToPlace = fluidData == MFluids.WATER$defaultState ? MFluids.WATER$defaultState : MBlocks.AIR$defaultState; + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, stateToPlace, option.flags()); return super.placeBlock(location, blockState); } 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 5255de607..34d2f0e65 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 @@ -18,8 +18,6 @@ public final class MBlocks { public static final Object SHULKER_BOX; public static final Object COMPOSTER; public static final Object SNOW; - public static final Object WATER; - public static final Object WATER$defaultState; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -39,7 +37,5 @@ public final class MBlocks { SHULKER_BOX = getById("shulker_box"); COMPOSTER = getById("composter"); SNOW = getById("snow"); - WATER = getById("water"); - WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java index a03660080..414d2472d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java @@ -7,6 +7,7 @@ public final class MFluids { private MFluids() {} public static final Object WATER; + public static final Object WATER$defaultState; public static final Object FLOWING_WATER; public static final Object LAVA; public static final Object FLOWING_LAVA; @@ -21,6 +22,7 @@ public final class MFluids { static { try { WATER = getById("water"); + WATER$defaultState = CoreReflections.method$Fluid$defaultFluidState.invoke(WATER); FLOWING_WATER = getById("flowing_water"); LAVA = getById("lava"); FLOWING_LAVA = getById("flowing_lava"); From 2f265e9836e81f9adaa1bba631b2611092dfd139 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 24 Jul 2025 23:01:08 +0800 Subject: [PATCH 42/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/behavior/DoubleHighBlockItemBehavior.java | 2 +- .../craftengine/bukkit/item/listener/ItemEventListener.java | 3 +++ .../bukkit/plugin/reflection/minecraft/MBlocks.java | 4 ++++ gradle.properties | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index fc8c6cb8c..c9c8949c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -30,7 +30,7 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()); UpdateOption option = UpdateOption.builder().updateNeighbors().updateClients().updateImmediate().updateKnownShape().build(); Object fluidData = FastNMS.INSTANCE.method$BlockGetter$getFluidState(level, blockPos); - Object stateToPlace = fluidData == MFluids.WATER$defaultState ? MFluids.WATER$defaultState : MBlocks.AIR$defaultState; + Object stateToPlace = fluidData == MFluids.WATER$defaultState ? MBlocks.WATER$defaultState : MBlocks.AIR$defaultState; FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, stateToPlace, option.flags()); return super.placeBlock(location, blockState); } 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 b10dd7ad7..ee42c4648 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 @@ -459,6 +459,7 @@ public class ItemEventListener implements Listener { } } + // 禁止附魔 @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onEnchant(PrepareItemEnchantEvent event) { ItemStack itemToEnchant = event.getItem(); @@ -471,6 +472,7 @@ public class ItemEventListener implements Listener { } } + // 自定义堆肥改了 @EventHandler(ignoreCancelled = true) public void onCompost(CompostItemEvent event) { ItemStack itemToCompost = event.getItem(); @@ -480,6 +482,7 @@ public class ItemEventListener implements Listener { event.setWillRaiseLevel(RandomUtils.generateRandomFloat(0, 1) < optionalCustomItem.get().settings().compostProbability()); } + // 用于附魔台纠正 @EventHandler(ignoreCancelled = true) public void onInventoryClick(InventoryClickEvent event) { if (!(event.getInventory() instanceof EnchantingInventory inventory)) return; 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 34d2f0e65..5255de607 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 @@ -18,6 +18,8 @@ public final class MBlocks { public static final Object SHULKER_BOX; public static final Object COMPOSTER; public static final Object SNOW; + public static final Object WATER; + public static final Object WATER$defaultState; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -37,5 +39,7 @@ public final class MBlocks { SHULKER_BOX = getById("shulker_box"); COMPOSTER = getById("composter"); SNOW = getById("snow"); + WATER = getById("water"); + WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); } } diff --git a/gradle.properties b/gradle.properties index fd7531d70..ec79d5386 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,7 +40,7 @@ commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 commons_lang3_version=3.17.0 sparrow_nbt_version=0.9.4 -sparrow_util_version=0.50.7 +sparrow_util_version=0.50.8 fastutil_version=8.5.15 netty_version=4.1.121.Final joml_version=1.10.8 From 779871e489c682febc76ce8e07eb45e99d81fccf Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 25 Jul 2025 17:27:27 +0800 Subject: [PATCH 43/83] =?UTF-8?q?=E6=9B=B4=E6=AD=A3=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E5=92=8C=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/DoubleHighBlockBehavior.java | 4 +--- common-files/src/main/resources/translations/en.yml | 2 +- common-files/src/main/resources/translations/zh_cn.yml | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index 40425df98..016979338 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -1,6 +1,5 @@ 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.plugin.reflection.minecraft.CoreReflections; @@ -20,7 +19,6 @@ import net.momirealms.craftengine.core.world.*; import java.util.Map; import java.util.concurrent.Callable; - public class DoubleHighBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property halfProperty; @@ -83,7 +81,7 @@ public class DoubleHighBlockBehavior extends BukkitBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - Property half = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.double.missing_half"); + Property half = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.double_high.missing_half"); return new DoubleHighBlockBehavior(block, half); } } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 3134565f4..3f4624266 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -292,7 +292,7 @@ warning.config.block.behavior.stairs.missing_half: "Issue found in file warning.config.block.behavior.stairs.missing_shape: "Issue found in file - The block '' is missing the required 'shape' property for 'stairs_block' behavior." warning.config.block.behavior.pressure_plate.missing_powered: "Issue found in file - The block '' is missing the required 'powered' property for 'pressure_plate_block' behavior." warning.config.block.behavior.grass.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'grass_block' behavior." -warning.config.block.behavior.double.missing_half: "Issue found in file - The block '' is missing the required 'half' property for 'double_block' behavior." +warning.config.block.behavior.double_high.missing_half: "Issue found in file - The block '' is missing the required 'half' property for 'double_block' behavior." warning.config.model.generation.missing_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." warning.config.model.generation.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" warning.config.model.generation.invalid_gui_light: "Issue found in file - The config '' is using an invalid gui-light option '' in 'generation' section. Allowed gui light options: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 8832c01d1..2666687a4 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -290,7 +290,7 @@ warning.config.block.behavior.stairs.missing_half: "在文件 warning.config.block.behavior.stairs.missing_shape: "在文件 发现问题 - 方块 '' 的 'stairs_block' 行为缺少必需的 'shape' 属性" warning.config.block.behavior.pressure_plate.missing_powered: "在文件 发现问题 - 方块 '' 的 'pressure_plate_block' 行为缺少必需的 'powered' 属性" warning.config.block.behavior.grass.missing_feature: "在文件 发现问题 - 方块 '' 的 'grass_block' 行为缺少必需的 'feature' 参数" -warning.config.block.behavior.double.missing_half: "在文件 发现问题 - 方块 '' 的 'double_block' 行为缺少必需的 'half' 属性" +warning.config.block.behavior.double_high.missing_half: "在文件 发现问题 - 方块 '' 的 'double_block' 行为缺少必需的 'half' 属性" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" From 032853ee7db50467350fa68723aedb490805d7cb Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 25 Jul 2025 19:20:32 +0800 Subject: [PATCH 44/83] =?UTF-8?q?tag=E9=98=B2=E5=91=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/core/item/ItemSettings.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index 9295d1745..b55cc6de9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -325,7 +325,13 @@ public class ItemSettings { })); registerFactory("tags", (value -> { List tags = MiscUtils.getAsStringList(value); - return settings -> settings.tags(tags.stream().map(Key::of).collect(Collectors.toSet())); + return settings -> settings.tags(tags.stream().map(it -> { + if (it.charAt(0) == '#') { + return Key.of(it.substring(1)); + } else { + return Key.of(it); + } + }).collect(Collectors.toSet())); })); registerFactory("equippable", (value -> { Map args = MiscUtils.castToMap(value, false); From 821a11b4780eeefdd7cfa2476ed58bb40219e44d Mon Sep 17 00:00:00 2001 From: halogly Date: Sat, 26 Jul 2025 00:25:09 +0800 Subject: [PATCH 45/83] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E7=9A=84=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E4=BA=A4=E4=BA=92=E6=96=B9=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/InteractUtils.java | 211 +++++++++++------- .../craftengine/core/block/BlockKeys.java | 3 + .../{EntityKeys.java => EntityTypeKeys.java} | 4 +- .../craftengine/core/item/ItemKeys.java | 3 + 4 files changed, 134 insertions(+), 87 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/entity/{EntityKeys.java => EntityTypeKeys.java} (98%) 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 39cbba3da..e610903df 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 @@ -2,11 +2,13 @@ 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.recipe.BukkitRecipeManager; import net.momirealms.craftengine.core.block.BlockKeys; -import net.momirealms.craftengine.core.entity.EntityKeys; +import net.momirealms.craftengine.core.entity.EntityTypeKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; @@ -15,9 +17,12 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; +import org.bukkit.GameMode; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Levelled; import org.bukkit.block.data.type.Bell; import org.bukkit.block.data.type.ChiseledBookshelf; +import org.bukkit.block.data.type.RespawnAnchor; import org.bukkit.entity.*; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -53,9 +58,43 @@ public class InteractUtils { registerInteraction(BlockKeys.GREEN_CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); registerInteraction(BlockKeys.RED_CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); registerInteraction(BlockKeys.BLACK_CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); - registerInteraction(BlockKeys.BEE_NEST, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.SHEARS) || item.vanillaId().equals(ItemKeys.GLASS_BOTTLE)); - registerInteraction(BlockKeys.BEEHIVE, (player, item, blockState, result) -> item.vanillaId().equals(ItemKeys.SHEARS) || item.vanillaId().equals(ItemKeys.GLASS_BOTTLE)); + registerInteraction(BlockKeys.COMMAND_BLOCK, (player, item, blockState, result) -> player.isOp() && player.getGameMode() == GameMode.CREATIVE); + registerInteraction(BlockKeys.CHAIN_COMMAND_BLOCK, (player, item, blockState, result) -> player.isOp() && player.getGameMode() == GameMode.CREATIVE); + registerInteraction(BlockKeys.REPEATING_COMMAND_BLOCK, (player, item, blockState, result) -> player.isOp() && player.getGameMode() == GameMode.CREATIVE); + registerInteraction(BlockKeys.JIGSAW, (player, item, blockState, result) -> player.isOp() && player.getGameMode() == GameMode.CREATIVE); + registerInteraction(BlockKeys.STRUCTURE_BLOCK, (player, item, blockState, result) -> player.isOp() && player.getGameMode() == GameMode.CREATIVE); + registerInteraction(BlockKeys.TEST_INSTANCE_BLOCK, (player, item, blockState, result) -> player.isOp() && player.getGameMode() == GameMode.CREATIVE); + 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.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> behaviors = item.getItemBehavior(); + if (behaviors.isPresent()) { + for (ItemBehavior behavior : behaviors.get()) { + if (behavior instanceof BlockItemBehavior) return false; + } + } + return true; + }); + registerInteraction(BlockKeys.DEEPSLATE_REDSTONE_ORE, (player, item, blockState, result) -> { + Optional> behaviors = item.getItemBehavior(); + if (behaviors.isPresent()) { + for (ItemBehavior behavior : behaviors.get()) { + if (behavior instanceof BlockItemBehavior) return false; + } + } + 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(); @@ -98,7 +137,16 @@ public class InteractUtils { if (!(blockState instanceof ChiseledBookshelf chiseledBookshelf)) return false; return DirectionUtils.toDirection(chiseledBookshelf.getFacing()) == result.getDirection(); }); + registerInteraction(BlockKeys.COMPOSTER, (player, item, blockState, result) -> { + if (item.getItem().getType().isCompostable()) return true; + return blockState instanceof Levelled levelled && levelled.getLevel() == levelled.getMaximumLevel(); + }); + registerInteraction(BlockKeys.RESPAWN_ANCHOR, (player, item, blockState, result) -> { + if (item.vanillaId().equals(ItemKeys.GLOWSTONE)) return true; + return blockState instanceof RespawnAnchor respawnAnchor && respawnAnchor.getCharges() != 0; + }); registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.FLOWER_POT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DISPENSER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DROPPER, (player, item, blockState, result) -> true); @@ -274,16 +322,6 @@ public class InteractUtils { registerInteraction(BlockKeys.RED_BED, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.BLACK_BED, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DRAGON_EGG, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.COMMAND_BLOCK, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.CHAIN_COMMAND_BLOCK, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.REPEATING_COMMAND_BLOCK, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.JIGSAW, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.STRUCTURE_BLOCK, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.TEST_INSTANCE_BLOCK, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.TEST_BLOCK, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.LIGHT, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.REDSTONE_ORE, (player, item, blockState, result) -> true); - registerInteraction(BlockKeys.DEEPSLATE_REDSTONE_ORE, (player, item, blockState, result) -> true); } static { @@ -292,68 +330,71 @@ public class InteractUtils { } static { - registerEntityInteraction(EntityKeys.BEE, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.FOX, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.FROG, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.PANDA, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.HOGLIN, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.OCELOT, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.RABBIT, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.TURTLE, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.CHICKEN, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.SNIFFER, (player, entity, item) -> canFeed(entity, item)); - registerEntityInteraction(EntityKeys.AXOLOTL, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.BEE, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.FOX, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.FROG, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.PANDA, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.HOGLIN, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.OCELOT, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.RABBIT, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.TURTLE, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.CHICKEN, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.SNIFFER, (player, entity, item) -> canFeed(entity, item)); + registerEntityInteraction(EntityTypeKeys.AXOLOTL, (player, entity, item) -> canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET))); - registerEntityInteraction(EntityKeys.COD, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.COD, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); - registerEntityInteraction(EntityKeys.SALMON, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.SALMON, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); - registerEntityInteraction(EntityKeys.TROPICAL_FISH, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.TROPICAL_FISH, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); - registerEntityInteraction(EntityKeys.PUFFERFISH, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.PUFFERFISH, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); - registerEntityInteraction(EntityKeys.TADPOLE, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.TADPOLE, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.WATER_BUCKET)); - registerEntityInteraction(EntityKeys.SNOW_GOLEM, (player, entity, item) -> shearable(entity, item)); - registerEntityInteraction(EntityKeys.SHEEP, (player, entity, item) -> canFeed(entity, item) || shearable(entity, item)); - registerEntityInteraction(EntityKeys.BOGGED, (player, entity, item) -> canFeed(entity, item) || shearable(entity, item)); - registerEntityInteraction(EntityKeys.MOOSHROOM, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.SNOW_GOLEM, (player, entity, item) -> + shearable(entity, item)); + registerEntityInteraction(EntityTypeKeys.SHEEP, (player, entity, item) -> + canFeed(entity, item) || shearable(entity, item)); + registerEntityInteraction(EntityTypeKeys.BOGGED, (player, entity, item) -> + canFeed(entity, item) || shearable(entity, item)); + registerEntityInteraction(EntityTypeKeys.MOOSHROOM, (player, entity, item) -> canFeed(entity, item) || shearable(entity, item) || (item != null && (item.vanillaId().equals(ItemKeys.BUCKET) || item.vanillaId().equals(ItemKeys.BOWL)))); - registerEntityInteraction(EntityKeys.COW, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.COW, (player, entity, item) -> canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.BUCKET))); - registerEntityInteraction(EntityKeys.GOAT, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.GOAT, (player, entity, item) -> canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.BUCKET))); - registerEntityInteraction(EntityKeys.CREEPER, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.CREEPER, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.FLINT_AND_STEEL)); - registerEntityInteraction(EntityKeys.PIGLIN, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.PIGLIN, (player, entity, item) -> item != null && item.vanillaId().equals(ItemKeys.GOLD_INGOT)); - registerEntityInteraction(EntityKeys.ARMADILLO, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.ARMADILLO, (player, entity, item) -> canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.BRUSH))); - registerEntityInteraction(EntityKeys.ZOMBIE_HORSE, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.ZOMBIE_HORSE, (player, entity, item) -> entity instanceof Tameable tameable && tameable.isTamed()); - registerEntityInteraction(EntityKeys.SKELETON_HORSE, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.SKELETON_HORSE, (player, entity, item) -> entity instanceof Tameable tameable && tameable.isTamed()); - registerEntityInteraction(EntityKeys.PIG, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.PIG, (player, entity, item) -> canFeed(entity, item) || (hasSaddle(player, entity) && !player.isSneaking())); - registerEntityInteraction(EntityKeys.STRIDER, (player, entity, item) -> + registerEntityInteraction(EntityTypeKeys.STRIDER, (player, entity, item) -> canFeed(entity, item) || (hasSaddle(player, entity) && !player.isSneaking())); - registerEntityInteraction(EntityKeys.WOLF, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); - registerEntityInteraction(EntityKeys.CAT, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); - registerEntityInteraction(EntityKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.BAMBOO_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.CHERRY_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.DARK_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.JUNGLE_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.MANGROVE_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.OAK_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.SPRUCE_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.MINECART, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityKeys.PARROT, (player, entity, item) -> { + registerEntityInteraction(EntityTypeKeys.WOLF, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); + registerEntityInteraction(EntityTypeKeys.CAT, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); + registerEntityInteraction(EntityTypeKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.BAMBOO_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.CHERRY_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.DARK_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.JUNGLE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.MANGROVE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.SPRUCE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.MINECART, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.PARROT, (player, entity, item) -> { if (item != null && item.is(Key.of("parrot_poisonous_food"))) return true; return canFeed(entity, item) || isPetOwner(player, entity); }); - registerEntityInteraction(EntityKeys.HAPPY_GHAST, (player, entity, item) -> { + registerEntityInteraction(EntityTypeKeys.HAPPY_GHAST, (player, entity, item) -> { if (!VersionHelper.isOrAbove1_21_6()) return false; if (entity instanceof HappyGhast happyGhast && !player.isSneaking()) { ItemStack bodyItem = happyGhast.getEquipment().getItem(EquipmentSlot.BODY); @@ -362,36 +403,36 @@ public class InteractUtils { } return canFeed(entity, item); }); - registerEntityInteraction(EntityKeys.ALLAY, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.HORSE, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.DONKEY, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.MULE, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.VILLAGER, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.WANDERING_TRADER, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.LLAMA, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.TRADER_LLAMA, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.CAMEL, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.ITEM_FRAME, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.GLOW_ITEM_FRAME, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.INTERACTION, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.ACACIA_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.BAMBOO_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.BIRCH_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.CHERRY_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.DARK_OAK_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.JUNGLE_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.MANGROVE_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.OAK_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.SPRUCE_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.CHEST_MINECART, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.FURNACE_MINECART, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.HOPPER_MINECART, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.COMMAND_BLOCK_MINECART, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.ALLAY, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.HORSE, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.DONKEY, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.MULE, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.VILLAGER, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.WANDERING_TRADER, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.LLAMA, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.TRADER_LLAMA, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.CAMEL, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.ITEM_FRAME, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.GLOW_ITEM_FRAME, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.INTERACTION, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.ACACIA_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.BAMBOO_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.BIRCH_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.CHERRY_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.DARK_OAK_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.JUNGLE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.MANGROVE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.OAK_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.SPRUCE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.CHEST_MINECART, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.FURNACE_MINECART, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.HOPPER_MINECART, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.COMMAND_BLOCK_MINECART, (player, entity, item) -> true); //<1.20.5 - registerEntityInteraction(EntityKeys.MINECART_CHEST, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.MINECART_HOPPER, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.MINECART_FURNACE, (player, entity, item) -> true); - registerEntityInteraction(EntityKeys.MINECART_COMMAND, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.MINECART_CHEST, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.MINECART_HOPPER, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.MINECART_FURNACE, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.MINECART_COMMAND, (player, entity, item) -> true); } private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { 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 9da2f4f3f..6f5daecc9 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 @@ -47,6 +47,7 @@ public final class BlockKeys { public static final Key TEST_BLOCK = Key.of("minecraft:test_block"); public static final Key LIGHT = Key.of("minecraft:light"); public static final Key DECORATED_POT = Key.of("minecraft:decorated_pot"); + public static final Key FLOWER_POT = Key.of("minecraft:flower_pot"); public static final Key CHISELED_BOOKSHELF = Key.of("minecraft:chiseled_bookshelf"); public static final Key REDSTONE_ORE = Key.of("minecraft:redstone_ore"); public static final Key DEEPSLATE_REDSTONE_ORE = Key.of("minecraft:deepslate_redstone_ore"); @@ -57,6 +58,8 @@ public final class BlockKeys { public static final Key CAULDRON = Key.of("minecraft:cauldron"); public static final Key WATER_CAULDRON = Key.of("minecraft:water_cauldron"); public static final Key LAVA_CAULDRON = Key.of("minecraft:lava_cauldron"); + public static final Key RESPAWN_ANCHOR = Key.of("minecraft:respawn_anchor"); + public static final Key LODESTONE = Key.of("minecraft:lodestone"); public static final Key CAKE = Key.of("minecraft:cake"); public static final Key CANDLE_CAKE = Key.of("minecraft:candle_cake"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityTypeKeys.java similarity index 98% rename from core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java rename to core/src/main/java/net/momirealms/craftengine/core/entity/EntityTypeKeys.java index 721302092..55b71f54a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityTypeKeys.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.entity; import net.momirealms.craftengine.core.util.Key; -public class EntityKeys { - private EntityKeys() {} +public class EntityTypeKeys { + private EntityTypeKeys() {} public static final Key BEE = Key.of("minecraft:BEE"); public static final Key FOX = Key.of("minecraft:FOX"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 148b73bb3..f49121f0d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -38,7 +38,10 @@ public class ItemKeys { public static final Key SHEARS = Key.of("minecraft:shears"); public static final Key BRUSH = Key.of("minecraft:brush"); public static final Key BOWL = Key.of("minecraft:bowl"); + public static final Key COMPASS = Key.of("minecraft:compass"); public static final Key GLASS_BOTTLE = Key.of("minecraft:glass_bottle"); + public static final Key LIGHT = Key.of("minecraft:light"); + public static final Key GLOWSTONE = Key.of("minecraft:glowstone"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE From 15e44d01aef692690c07e94177a72f448bb4219c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 26 Jul 2025 02:50:57 +0800 Subject: [PATCH 46/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=A4=9A=E8=A1=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/font/AbstractFontManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index b7789dc4c..bb4c46dd2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -368,7 +368,13 @@ public abstract class AbstractFontManager implements FontManager { if (keywords.isEmpty()) { throw new LocalizedResourceConfigException("warning.config.emoji.missing_keywords", path, id); } - String content = section.getOrDefault("content", "").toString(); + Object rawContent = section.getOrDefault("content", ""); + String content; + if (rawContent instanceof List list) { + content = list.stream().map(Object::toString).collect(Collectors.joining()); + } else { + content = rawContent.toString(); + } String image = null; if (section.containsKey("image")) { String rawImage = section.get("image").toString(); From f2d9921d26dd7f57764d487f5993c5ec431ed40e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 26 Jul 2025 16:19:07 +0800 Subject: [PATCH 47/83] =?UTF-8?q?=E8=A1=A5=E9=BD=90=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E9=93=BE=E5=BC=8F=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/plugin/context/CommonParameterProvider.java | 1 + .../plugin/context/parameter/FurnitureParameterProvider.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CommonParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CommonParameterProvider.java index 89af9a7b0..d3b7dc037 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CommonParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CommonParameterProvider.java @@ -8,6 +8,7 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; +//TODO 需要为random指定id public class CommonParameterProvider implements AdditionalParameterProvider { private double lastRandom = -1; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java index 2f49aca37..50ccfc7a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java @@ -15,6 +15,10 @@ public class FurnitureParameterProvider implements ChainParameterProvider furniture.position().x()); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, furniture -> furniture.position().y()); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, furniture -> furniture.position().z()); + CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Furniture::position); } @SuppressWarnings("unchecked") From 14c30982f78b1cf7475eb7bb4df3567b62382dcb Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 26 Jul 2025 17:40:29 +0800 Subject: [PATCH 48/83] =?UTF-8?q?=E7=A8=8D=E5=BE=AE=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E4=B8=80=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/build.gradle.kts | 2 +- .../worldedit/FastAsyncWorldEditDelegate.java | 4 -- bukkit/legacy/build.gradle.kts | 2 +- bukkit/loader/build.gradle.kts | 2 +- bukkit/paper-loader/build.gradle.kts | 2 +- .../item/listener/ItemEventListener.java | 46 ++++++++++--------- .../classpath/PaperClassPathAppender.java | 27 ++++++----- .../craftengine/bukkit/util/EntityUtils.java | 4 +- .../bukkit/util/InteractUtils.java | 45 +++++++++++++----- .../craftengine/bukkit/util/ItemTags.java | 5 -- core/build.gradle.kts | 2 +- .../core/item/AbstractItemManager.java | 1 - .../core/plugin/config/Config.java | 5 +- gradle.properties | 2 +- 14 files changed, 86 insertions(+), 63 deletions(-) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 78efcd56d..c9bf92f91 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta13" + id("com.gradleup.shadow") version "9.0.0-rc2" id("maven-publish") } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java index 04669495f..e116d6e6c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java @@ -1,12 +1,9 @@ package net.momirealms.craftengine.bukkit.compatibility.worldedit; -import com.fastasyncworldedit.bukkit.FaweBukkitWorld; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; -import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; -import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.ExtentTraverser; import com.fastasyncworldedit.core.util.ProcessorTraverser; import com.sk89q.worldedit.EditSession; @@ -27,7 +24,6 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.WorldStorageInjector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.EmptyBlock; diff --git a/bukkit/legacy/build.gradle.kts b/bukkit/legacy/build.gradle.kts index da89d9df8..2de912779 100644 --- a/bukkit/legacy/build.gradle.kts +++ b/bukkit/legacy/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta13" + id("com.gradleup.shadow") version "9.0.0-rc2" } repositories { diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index 9e4762b96..29d893949 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta13" + id("com.gradleup.shadow") version "9.0.0-rc2" id("de.eldoria.plugin-yml.bukkit") version "0.7.1" } diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index ac2894f04..1d5ce6703 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -1,7 +1,7 @@ import net.minecrell.pluginyml.paper.PaperPluginDescription plugins { - id("com.gradleup.shadow") version "9.0.0-beta13" + id("com.gradleup.shadow") version "9.0.0-rc2" id("de.eldoria.plugin-yml.paper") version "0.7.1" } 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 73471279c..5145a7b05 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 @@ -77,6 +77,7 @@ public class ItemEventListener implements Listener { if (ItemUtils.isEmpty(itemInHand)) return; Optional> 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 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> 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 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() diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java index ddacca6b9..24a89e13d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java @@ -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 diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index e7fe96bb1..851c8e41b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -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; 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 e610903df..47ff02f32 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 @@ -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, 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> 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 item) { - Key key = Key.of(String.valueOf(entity.getType())); - TriFunction, 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, Boolean> func = ENTITY_INTERACTIONS.get(KeyUtils.resourceLocationToKey(id)); return func != null && func.apply(player, entity, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java index 6028485a4..1f35e3e90 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java @@ -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; diff --git a/core/build.gradle.kts b/core/build.gradle.kts index d41f1c2f1..df535d1cd 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta13" + id("com.gradleup.shadow") version "9.0.0-rc2" id("maven-publish") } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 6865d2cf7..0bb7a59cf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -16,7 +16,6 @@ import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; -import net.momirealms.craftengine.core.pack.host.ResourcePackHosts; import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 04f031e4e..0f3c2d5d6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -20,7 +20,10 @@ import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MinecraftVersion; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.InjectionTarget; import net.momirealms.craftengine.core.world.chunk.storage.CompressionMethod; diff --git a/gradle.properties b/gradle.properties index ec79d5386..f9c9970e9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.18 -nms_helper_version=1.0.37 +nms_helper_version=1.0.38 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 3b5a2855ab8793e5518dcb43fb38170c69f1abb9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 26 Jul 2025 17:43:38 +0800 Subject: [PATCH 49/83] =?UTF-8?q?=E6=8F=90=E5=8F=96=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E7=B1=BB=E5=9E=8B=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/bukkit/util/EntityUtils.java | 9 +++++++++ .../craftengine/bukkit/util/InteractUtils.java | 9 ++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index 851c8e41b..a4b87cde2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -2,6 +2,8 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.Location; @@ -35,4 +37,11 @@ public class EntityUtils { return LegacyEntityUtils.spawnEntity(world, loc, type, function); } } + + public static Key getEntityType(Entity entity) { + 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); + return KeyUtils.resourceLocationToKey(id); + } } \ No newline at end of file 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 47ff02f32..95b2f2acb 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 @@ -4,8 +4,6 @@ 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; @@ -485,10 +483,7 @@ public class InteractUtils { } public static boolean isEntityInteractable(Player player, Entity entity, @Nullable Item item) { - 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, Boolean> func = ENTITY_INTERACTIONS.get(KeyUtils.resourceLocationToKey(id)); + TriFunction, Boolean> func = ENTITY_INTERACTIONS.get(EntityUtils.getEntityType(entity)); return func != null && func.apply(player, entity, item); } @@ -507,7 +502,7 @@ public class InteractUtils { } private static boolean canFeed(Entity entity, Item item) { - return entity instanceof Animals animals && item.is(Key.of(animals.getType().toString().toLowerCase() + "_food")); + return entity instanceof Animals && item.is(Key.of(EntityUtils.getEntityType(entity).value() + "_food")); } private static boolean hasSaddle(Player player, Entity entity) { From 422c091bfacc1224b31c00dbcf8055214429bf0c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 26 Jul 2025 17:54:58 +0800 Subject: [PATCH 50/83] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/listener/ItemEventListener.java | 11 +++++++++- .../plugin/user/BukkitServerPlayer.java | 21 +++++++++++++++++++ .../core/entity/player/Player.java | 4 ++++ 3 files changed, 35 insertions(+), 1 deletion(-) 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 5145a7b05..2b2277636 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 @@ -71,7 +71,11 @@ public class ItemEventListener implements Listener { Entity entity = event.getRightClicked(); BukkitServerPlayer serverPlayer = this.plugin.adapt(player); if (serverPlayer == null) return; + InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + // prevent duplicated interact air events + serverPlayer.updateLastInteractEntityTick(hand); + Item itemInHand = serverPlayer.getItemInHand(hand); if (ItemUtils.isEmpty(itemInHand)) return; @@ -350,11 +354,16 @@ public class ItemEventListener implements Listener { return; // Gets the item in hand InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + // prevents duplicated events + if (serverPlayer.lastInteractEntityCheck(hand)) { + return; + } + Item itemInHand = serverPlayer.getItemInHand(hand); // should never be null if (ItemUtils.isEmpty(itemInHand)) return; - // todo 真的需要这个吗 + // TODO 有必要存在吗? if (cancelEventIfHasInteraction(event, serverPlayer, hand)) { return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 5e78643a6..2eef99bbb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -76,6 +76,9 @@ public class BukkitServerPlayer extends Player { private Key clientSideDimension; // check main hand/offhand interaction private int lastSuccessfulInteraction; + // to prevent duplicated events + private int lastInteractEntityWithMainHand; + private int lastInteractEntityWithOffHand; // re-sync attribute timely to prevent some bugs private long lastAttributeSyncTime; // for breaking blocks @@ -234,6 +237,24 @@ public class BukkitServerPlayer extends Player { return this.lastSuccessfulInteraction; } + @Override + public void updateLastInteractEntityTick(@NotNull InteractionHand hand) { + if (hand == InteractionHand.MAIN_HAND) { + this.lastInteractEntityWithMainHand = gameTicks(); + } else { + this.lastInteractEntityWithOffHand = gameTicks(); + } + } + + @Override + public boolean lastInteractEntityCheck(@NotNull InteractionHand hand) { + if (hand == InteractionHand.MAIN_HAND) { + return gameTicks() == this.lastInteractEntityWithMainHand; + } else { + return gameTicks() == this.lastInteractEntityWithOffHand; + } + } + @Override public int gameTicks() { return this.gameTicks; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 073a8d41c..9cc7ac42d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -68,6 +68,10 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract int lastSuccessfulInteractionTick(); + public abstract void updateLastInteractEntityTick(@NotNull InteractionHand hand); + + public abstract boolean lastInteractEntityCheck(@NotNull InteractionHand hand); + public abstract int gameTicks(); public abstract void swingHand(InteractionHand hand); From 0222c74aabc27d9c0e77bd5b19e0357a34d1fd68 Mon Sep 17 00:00:00 2001 From: halogly Date: Sat, 26 Jul 2025 21:31:42 +0800 Subject: [PATCH 51/83] =?UTF-8?q?=E6=9B=B4=E6=96=B0EntityTypeKey=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=89=B9=E6=AE=8A=E5=8F=AF=E9=AA=91=E4=B9=98?= =?UTF-8?q?=E7=94=9F=E7=89=A9=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/InteractUtils.java | 46 +++--- .../core/entity/EntityTypeKeys.java | 151 +++++++++--------- .../craftengine/core/item/ItemKeys.java | 2 + 3 files changed, 101 insertions(+), 98 deletions(-) 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 95b2f2acb..c63b370d0 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 @@ -392,31 +392,32 @@ public class InteractUtils { registerEntityInteraction(EntityTypeKeys.SKELETON_HORSE, (player, entity, item) -> entity instanceof Tameable tameable && tameable.isTamed()); registerEntityInteraction(EntityTypeKeys.PIG, (player, entity, item) -> - canFeed(entity, item) || (hasSaddle(player, entity) && !player.isSneaking())); + canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.SADDLE) && !hasSaddle(player, entity)) || (hasSaddle(player, entity) && !player.isSneaking())); registerEntityInteraction(EntityTypeKeys.STRIDER, (player, entity, item) -> - canFeed(entity, item) || (hasSaddle(player, entity) && !player.isSneaking())); + canFeed(entity, item) || (item != null && item.vanillaId().equals(ItemKeys.SADDLE) && !hasSaddle(player, entity)) || (hasSaddle(player, entity) && !player.isSneaking())); registerEntityInteraction(EntityTypeKeys.WOLF, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); registerEntityInteraction(EntityTypeKeys.CAT, (player, entity, item) -> canFeed(entity, item) || isPetOwner(player, entity)); - registerEntityInteraction(EntityTypeKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityTypeKeys.BAMBOO_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityTypeKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityTypeKeys.CHERRY_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityTypeKeys.DARK_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityTypeKeys.JUNGLE_BOAT, (player, entity, item) -> !player.isSneaking()); - registerEntityInteraction(EntityTypeKeys.MANGROVE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.BOAT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityTypeKeys.OAK_BOAT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityTypeKeys.SPRUCE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.BIRCH_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.JUNGLE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.ACACIA_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.DARK_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.MANGROVE_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.CHERRY_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.PALE_OAK_BOAT, (player, entity, item) -> !player.isSneaking()); + registerEntityInteraction(EntityTypeKeys.BAMBOO_RAFT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityTypeKeys.MINECART, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityTypeKeys.PARROT, (player, entity, item) -> { if (item != null && item.is(Key.of("parrot_poisonous_food"))) return true; return canFeed(entity, item) || isPetOwner(player, entity); }); registerEntityInteraction(EntityTypeKeys.HAPPY_GHAST, (player, entity, item) -> { - if (!VersionHelper.isOrAbove1_21_6()) return false; + if (item != null && item.vanillaId().equals(ItemKeys.HARNESS)) return true; if (entity instanceof HappyGhast happyGhast && !player.isSneaking()) { ItemStack bodyItem = happyGhast.getEquipment().getItem(EquipmentSlot.BODY); - Item wrap = BukkitItemManager.instance().wrap(bodyItem); - return wrap.is(Key.of("harnesses")); + return BukkitItemManager.instance().wrap(bodyItem).is(Key.of("harnesses")); } return canFeed(entity, item); }); @@ -432,24 +433,21 @@ public class InteractUtils { registerEntityInteraction(EntityTypeKeys.ITEM_FRAME, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.GLOW_ITEM_FRAME, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.INTERACTION, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.ACACIA_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.BAMBOO_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.BIRCH_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.CHERRY_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.DARK_OAK_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.JUNGLE_CHEST_BOAT, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.MANGROVE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.CHEST_BOAT, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.OAK_CHEST_BOAT, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.SPRUCE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.BIRCH_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.JUNGLE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.ACACIA_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.DARK_OAK_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.MANGROVE_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.CHERRY_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.PALE_OAK_CHEST_BOAT, (player, entity, item) -> true); + registerEntityInteraction(EntityTypeKeys.BAMBOO_CHEST_RAFT, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.CHEST_MINECART, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.FURNACE_MINECART, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.HOPPER_MINECART, (player, entity, item) -> true); registerEntityInteraction(EntityTypeKeys.COMMAND_BLOCK_MINECART, (player, entity, item) -> true); - //<1.20.5 - registerEntityInteraction(EntityTypeKeys.MINECART_CHEST, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.MINECART_HOPPER, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.MINECART_FURNACE, (player, entity, item) -> true); - registerEntityInteraction(EntityTypeKeys.MINECART_COMMAND, (player, entity, item) -> true); } private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityTypeKeys.java b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityTypeKeys.java index 55b71f54a..c4829722a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/EntityTypeKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/EntityTypeKeys.java @@ -5,77 +5,80 @@ import net.momirealms.craftengine.core.util.Key; public class EntityTypeKeys { private EntityTypeKeys() {} - public static final Key BEE = Key.of("minecraft:BEE"); - public static final Key FOX = Key.of("minecraft:FOX"); - public static final Key FROG = Key.of("minecraft:FROG"); - public static final Key PANDA = Key.of("minecraft:PANDA"); - public static final Key SHEEP = Key.of("minecraft:SHEEP"); - public static final Key BOGGED = Key.of("minecraft:BOGGED"); - public static final Key SNOW_GOLEM = Key.of("minecraft:SNOW_GOLEM"); - public static final Key HOGLIN = Key.of("minecraft:HOGLIN"); - public static final Key OCELOT = Key.of("minecraft:OCELOT"); - public static final Key RABBIT = Key.of("minecraft:RABBIT"); - public static final Key TURTLE = Key.of("minecraft:TURTLE"); - public static final Key AXOLOTL = Key.of("minecraft:AXOLOTL"); - public static final Key CHICKEN = Key.of("minecraft:CHICKEN"); - public static final Key SNIFFER = Key.of("minecraft:SNIFFER"); - public static final Key ARMADILLO = Key.of("minecraft:ARMADILLO"); - public static final Key COD = Key.of("minecraft:COD"); - public static final Key SALMON = Key.of("minecraft:SALMON"); - public static final Key TROPICAL_FISH = Key.of("minecraft:TROPICAL_FISH"); - public static final Key PUFFERFISH = Key.of("minecraft:PUFFERFISH"); - public static final Key TADPOLE = Key.of("minecraft:TADPOLE"); - public static final Key COW = Key.of("minecraft:COW"); - public static final Key MOOSHROOM = Key.of("minecraft:MOOSHROOM"); - public static final Key GOAT = Key.of("minecraft:GOAT"); - public static final Key PIG = Key.of("minecraft:PIG"); - public static final Key STRIDER = Key.of("minecraft:STRIDER"); - public static final Key WOLF = Key.of("minecraft:WOLF"); - public static final Key CAT = Key.of("minecraft:CAT"); - public static final Key PARROT = Key.of("minecraft:PARROT"); - public static final Key ACACIA_BOAT = Key.of("minecraft:ACACIA_BOAT"); - public static final Key BAMBOO_BOAT = Key.of("minecraft:BAMBOO_BOAT"); - public static final Key BIRCH_BOAT = Key.of("minecraft:BIRCH_BOAT"); - public static final Key CHERRY_BOAT = Key.of("minecraft:CHERRY_BOAT"); - public static final Key DARK_OAK_BOAT = Key.of("minecraft:DARK_OAK_BOAT"); - public static final Key JUNGLE_BOAT = Key.of("minecraft:JUNGLE_BOAT"); - public static final Key MANGROVE_BOAT = Key.of("minecraft:MANGROVE_BOAT"); - public static final Key OAK_BOAT = Key.of("minecraft:OAK_BOAT"); - public static final Key SPRUCE_BOAT = Key.of("minecraft:SPRUCE_BOAT"); - public static final Key MINECART = Key.of("minecraft:MINECART"); - public static final Key HAPPY_GHAST = Key.of("minecraft:HAPPY_GHAST"); - public static final Key PIGLIN = Key.of("minecraft:PIGLIN"); - public static final Key CREEPER = Key.of("minecraft:CREEPER"); - public static final Key ALLAY = Key.of("minecraft:ALLAY"); - public static final Key HORSE = Key.of("minecraft:HORSE"); - public static final Key ZOMBIE_HORSE = Key.of("minecraft:ZOMBIE_HORSE"); - public static final Key SKELETON_HORSE = Key.of("minecraft:SKELETON_HORSE"); - public static final Key DONKEY = Key.of("minecraft:DONKEY"); - public static final Key MULE = Key.of("minecraft:MULE"); - public static final Key VILLAGER = Key.of("minecraft:VILLAGER"); - public static final Key WANDERING_TRADER = Key.of("minecraft:WANDERING_TRADER"); - public static final Key LLAMA = Key.of("minecraft:LLAMA"); - public static final Key TRADER_LLAMA = Key.of("minecraft:TRADER_LLAMA"); - public static final Key CAMEL = Key.of("minecraft:CAMEL"); - public static final Key ITEM_FRAME = Key.of("minecraft:ITEM_FRAME"); - public static final Key GLOW_ITEM_FRAME = Key.of("minecraft:GLOW_ITEM_FRAME"); - public static final Key INTERACTION = Key.of("minecraft:INTERACTION"); - public static final Key ACACIA_CHEST_BOAT = Key.of("minecraft:ACACIA_CHEST_BOAT"); - public static final Key BAMBOO_CHEST_BOAT = Key.of("minecraft:BAMBOO_CHEST_BOAT"); - public static final Key BIRCH_CHEST_BOAT = Key.of("minecraft:BIRCH_CHEST_BOAT"); - public static final Key CHERRY_CHEST_BOAT = Key.of("minecraft:CHERRY_CHEST_BOAT"); - public static final Key DARK_OAK_CHEST_BOAT = Key.of("minecraft:DARK_OAK_CHEST_BOAT"); - public static final Key JUNGLE_CHEST_BOAT = Key.of("minecraft:JUNGLE_CHEST_BOAT"); - public static final Key MANGROVE_CHEST_BOAT = Key.of("minecraft:MANGROVE_CHEST_BOAT"); - public static final Key OAK_CHEST_BOAT = Key.of("minecraft:OAK_CHEST_BOAT"); - public static final Key SPRUCE_CHEST_BOAT = Key.of("minecraft:SPRUCE_CHEST_BOAT"); - public static final Key CHEST_MINECART = Key.of("minecraft:CHEST_MINECART"); - public static final Key FURNACE_MINECART = Key.of("minecraft:FURNACE_MINECART"); - public static final Key HOPPER_MINECART = Key.of("minecraft:HOPPER_MINECART"); - public static final Key COMMAND_BLOCK_MINECART = Key.of("minecraft:COMMAND_BLOCK_MINECART"); - //<1.20.5 - public static final Key MINECART_CHEST = Key.of("minecraft:MINECART_CHEST"); - public static final Key MINECART_FURNACE = Key.of("minecraft:MINECART_FURNACE"); - public static final Key MINECART_HOPPER = Key.of("minecraft:MINECART_HOPPER"); - public static final Key MINECART_COMMAND = Key.of("minecraft:MINECART_COMMAND"); -} + public static final Key BEE = Key.of("minecraft:bee"); + public static final Key FOX = Key.of("minecraft:fox"); + public static final Key FROG = Key.of("minecraft:frog"); + public static final Key PANDA = Key.of("minecraft:panda"); + public static final Key SHEEP = Key.of("minecraft:sheep"); + public static final Key BOGGED = Key.of("minecraft:bogged"); + public static final Key SNOW_GOLEM = Key.of("minecraft:snow_golem"); + public static final Key HOGLIN = Key.of("minecraft:hoglin"); + public static final Key OCELOT = Key.of("minecraft:ocelot"); + public static final Key RABBIT = Key.of("minecraft:rabbit"); + public static final Key TURTLE = Key.of("minecraft:turtle"); + public static final Key AXOLOTL = Key.of("minecraft:axolotl"); + public static final Key CHICKEN = Key.of("minecraft:chicken"); + public static final Key SNIFFER = Key.of("minecraft:sniffer"); + public static final Key ARMADILLO = Key.of("minecraft:armadillo"); + public static final Key COD = Key.of("minecraft:cod"); + public static final Key SALMON = Key.of("minecraft:salmon"); + public static final Key TROPICAL_FISH = Key.of("minecraft:tropical_fish"); + public static final Key PUFFERFISH = Key.of("minecraft:pufferfish"); + public static final Key TADPOLE = Key.of("minecraft:tadpole"); + public static final Key COW = Key.of("minecraft:cow"); + public static final Key MOOSHROOM = Key.of("minecraft:mooshroom"); + public static final Key GOAT = Key.of("minecraft:goat"); + public static final Key PIG = Key.of("minecraft:pig"); + public static final Key STRIDER = Key.of("minecraft:strider"); + public static final Key WOLF = Key.of("minecraft:wolf"); + public static final Key CAT = Key.of("minecraft:cat"); + public static final Key PARROT = Key.of("minecraft:parrot"); + + public static final Key HAPPY_GHAST = Key.of("minecraft:happy_ghast"); + public static final Key PIGLIN = Key.of("minecraft:piglin"); + public static final Key CREEPER = Key.of("minecraft:creeper"); + public static final Key ALLAY = Key.of("minecraft:allay"); + public static final Key HORSE = Key.of("minecraft:horse"); + public static final Key ZOMBIE_HORSE = Key.of("minecraft:zombie_horse"); + public static final Key SKELETON_HORSE = Key.of("minecraft:skeleton_horse"); + public static final Key DONKEY = Key.of("minecraft:donkey"); + public static final Key MULE = Key.of("minecraft:mule"); + public static final Key VILLAGER = Key.of("minecraft:villager"); + public static final Key WANDERING_TRADER = Key.of("minecraft:wandering_trader"); + public static final Key LLAMA = Key.of("minecraft:llama"); + public static final Key TRADER_LLAMA = Key.of("minecraft:trader_llama"); + public static final Key CAMEL = Key.of("minecraft:camel"); + public static final Key ITEM_FRAME = Key.of("minecraft:item_frame"); + public static final Key GLOW_ITEM_FRAME = Key.of("minecraft:glow_item_frame"); + public static final Key INTERACTION = Key.of("minecraft:interaction"); + + public static final Key BOAT = Key.of("minecraft:boat"); + public static final Key OAK_BOAT = Key.of("minecraft:oak_boat"); + public static final Key SPRUCE_BOAT = Key.of("minecraft:spruce_boat"); + public static final Key BIRCH_BOAT = Key.of("minecraft:birch_boat"); + public static final Key JUNGLE_BOAT = Key.of("minecraft:jungle_boat"); + public static final Key ACACIA_BOAT = Key.of("minecraft:acacia_boat"); + public static final Key DARK_OAK_BOAT = Key.of("minecraft:dark_oak_boat"); + public static final Key MANGROVE_BOAT = Key.of("minecraft:mangrove_boat"); + public static final Key CHERRY_BOAT = Key.of("minecraft:cherry_boat"); + public static final Key PALE_OAK_BOAT = Key.of("minecraft:pale_oak_boat"); + public static final Key BAMBOO_RAFT = Key.of("minecraft:bamboo_raft"); + + public static final Key CHEST_BOAT = Key.of("minecraft:chest_boat"); + public static final Key OAK_CHEST_BOAT = Key.of("minecraft:oak_chest_boat"); + public static final Key SPRUCE_CHEST_BOAT = Key.of("minecraft:spruce_chest_boat"); + public static final Key BIRCH_CHEST_BOAT = Key.of("minecraft:birch_chest_boat"); + public static final Key JUNGLE_CHEST_BOAT = Key.of("minecraft:jungle_chest_boat"); + public static final Key ACACIA_CHEST_BOAT = Key.of("minecraft:acacia_chest_boat"); + public static final Key DARK_OAK_CHEST_BOAT = Key.of("minecraft:dark_oak_chest_boat"); + public static final Key MANGROVE_CHEST_BOAT = Key.of("minecraft:mangrove_chest_boat"); + public static final Key CHERRY_CHEST_BOAT = Key.of("minecraft:cherry_chest_boat"); + public static final Key PALE_OAK_CHEST_BOAT = Key.of("minecraft:pale_oak_chest_boat"); + public static final Key BAMBOO_CHEST_RAFT = Key.of("minecraft:bamboo_chest_raft"); + + public static final Key MINECART = Key.of("minecraft:minecart"); + public static final Key CHEST_MINECART = Key.of("minecraft:chest_minecart"); + public static final Key FURNACE_MINECART = Key.of("minecraft:furnace_minecart"); + public static final Key HOPPER_MINECART = Key.of("minecraft:hopper_minecart"); + public static final Key COMMAND_BLOCK_MINECART = Key.of("minecraft:command_block_minecart"); +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index f49121f0d..05b0bc297 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -42,6 +42,8 @@ public class ItemKeys { public static final Key GLASS_BOTTLE = Key.of("minecraft:glass_bottle"); public static final Key LIGHT = Key.of("minecraft:light"); public static final Key GLOWSTONE = Key.of("minecraft:glowstone"); + public static final Key SADDLE = Key.of("minecraft:saddle"); + public static final Key HARNESS = Key.of("minecraft:harness"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE From fd6eb13404c195aefa9c1d356669bfd152e65e63 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 26 Jul 2025 23:07:10 +0800 Subject: [PATCH 52/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=BD=BF=E7=94=A8nbt=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/AbstractItemManager.java | 10 ++++------ .../core/item/modifier/TagsModifier.java | 19 +++++++++++++++---- gradle.properties | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 0bb7a59cf..2635e6d7d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -554,12 +554,10 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return new DyedColorModifier<>(0 << 24 /*不可省略*/ | MCUtils.fastFloor(vector3f.x) << 16 | MCUtils.fastFloor(vector3f.y) << 8 | MCUtils.fastFloor(vector3f.z)); } }, "dyed-color"); - if (!VersionHelper.isOrAbove1_21_5()) { - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - return new TagsModifier<>(data); - }, "tags", "tag", "nbt"); - } + registerDataType((obj) -> { + Map data = MiscUtils.castToMap(obj, false); + return new TagsModifier<>(data); + }, "tags", "tag", "nbt"); registerDataType((object -> { MutableInt mutableInt = new MutableInt(0); List attributeModifiers = ResourceConfigUtils.parseConfigAsList(object, (map) -> { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java index b264c9c33..16a8ec444 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java @@ -1,10 +1,12 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.TypeUtils; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -40,12 +42,21 @@ public class TagsModifier implements ItemDataModifier { // TODO NOT PERFECT @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - for (Map.Entry entry : this.arguments.entrySet()) { - Tag previous = item.getTag(entry.getKey()); + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getSparrowNBTComponent(ComponentKeys.CUSTOM_DATA); if (previous != null) { - networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + networkData.put(ComponentKeys.CUSTOM_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { - networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + networkData.put(ComponentKeys.CUSTOM_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + for (Map.Entry entry : this.arguments.entrySet()) { + Tag previous = item.getTag(entry.getKey()); + if (previous != null) { + networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } return item; diff --git a/gradle.properties b/gradle.properties index f9c9970e9..0975bcb33 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.5 +project_version=0.0.60.6 config_version=43 lang_version=22 project_group=net.momirealms From 02be890499fe0cc06343c1049aeddacfcde98456 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 26 Jul 2025 23:11:10 +0800 Subject: [PATCH 53/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E6=9C=89=E6=95=88=E6=80=A7=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/network/PacketConsumers.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 4a2ba84c7..a7d0e2626 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1602,6 +1602,10 @@ public class PacketConsumers { } mainThreadTask = () -> { + if (!furniture.isValid()) { + return; + } + FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); if (EventUtils.fireAndCheckCancel(interactEvent)) { return; From 7aef195d7c1629fa2a1bfe301a035e933fb3d0ab Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 27 Jul 2025 06:41:16 +0800 Subject: [PATCH 54/83] =?UTF-8?q?refactor(bukkit):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=96=AD=E5=BC=80=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/BukkitSenderFactory.java | 2 +- .../plugin/network/BukkitNetworkManager.java | 47 ++++++++++++------- .../plugin/user/BukkitServerPlayer.java | 19 ++++++-- .../core/entity/player/Player.java | 2 + .../core/plugin/network/NetWorkUser.java | 2 + .../core/plugin/network/NetworkManager.java | 16 +++++-- gradle.properties | 2 +- 7 files changed, 63 insertions(+), 27 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java index b4d3e40e4..76625f057 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java @@ -44,7 +44,7 @@ public class BukkitSenderFactory extends SenderFactory packetConsumer; - private final BiConsumer> packetsConsumer; - private final BiConsumer immediatePacketConsumer; - private final BiConsumer> immediatePacketsConsumer; + private final TriConsumer packetConsumer; + private final TriConsumer, Object> packetsConsumer; + private final TriConsumer immediatePacketConsumer; + private final TriConsumer, Runnable> immediatePacketsConsumer; private final BukkitCraftEngine plugin; private final Map users = new ConcurrentHashMap<>(); @@ -105,14 +105,23 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.registerPacketHandlers(); // set up packet senders this.packetConsumer = FastNMS.INSTANCE::method$Connection$send; - this.packetsConsumer = ((connection, packets) -> { + this.packetsConsumer = ((connection, packets, sendListener) -> { Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); - this.packetConsumer.accept(connection, bundle); + this.packetConsumer.accept(connection, bundle, sendListener); }); - this.immediatePacketConsumer = ChannelOutboundInvoker::writeAndFlush; - this.immediatePacketsConsumer = (channel, packets) -> { + this.immediatePacketConsumer = (channel, packet, sendListener) -> { + ChannelFuture future = channel.writeAndFlush(packet); + if (sendListener == null) return; + future.addListener((ChannelFutureListener) channelFuture -> { + sendListener.run(); + if (!channelFuture.isSuccess()) { + channelFuture.channel().pipeline().fireExceptionCaught(channelFuture.cause()); + } + }); + }; + this.immediatePacketsConsumer = (channel, packets, sendListener) -> { Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); - this.immediatePacketConsumer.accept(channel, bundle); + this.immediatePacketConsumer.accept(channel, bundle, sendListener); }; // set up mod channel this.plugin.javaPlugin().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL, this); @@ -127,7 +136,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes Channel channel = future.channel(); injectServerChannel(channel); this.injectedChannels.add(channel); - }, (object) -> {}); + }, (object) -> { + }); CoreReflections.field$ServerConnectionListener$channels.set(serverConnection, monitor); } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to init server connection", e); @@ -206,7 +216,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.resetUserArray(); if (VersionHelper.isFolia()) { player.getScheduler().runAtFixedRate(plugin.javaPlugin(), (t) -> user.tick(), - () -> {}, 1, 1); + () -> { + }, 1, 1); } } } @@ -305,20 +316,20 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } @Override - public void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately) { + public void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately, Runnable sendListener) { if (immediately) { - this.immediatePacketConsumer.accept(player.nettyChannel(), packet); + this.immediatePacketConsumer.accept(player.nettyChannel(), packet, sendListener); } else { - this.packetConsumer.accept(player.connection(), packet); + this.packetConsumer.accept(player.connection(), packet, sendListener != null ? FastNMS.INSTANCE.method$PacketSendListener$thenRun(sendListener) : null); } } @Override - public void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately) { + public void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately, Runnable sendListener) { if (immediately) { - this.immediatePacketsConsumer.accept(player.nettyChannel(), packet); + this.immediatePacketsConsumer.accept(player.nettyChannel(), packet, sendListener); } else { - this.packetsConsumer.accept(player.connection(), packet); + this.packetsConsumer.accept(player.connection(), packet, sendListener != null ? FastNMS.INSTANCE.method$PacketSendListener$thenRun(sendListener) : null); } } @@ -685,7 +696,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes ByteBuf temp = ctx.alloc().buffer(); try { if (compressor != null) { - callEncode(compressor, ctx, input, temp); + callEncode(compressor, ctx, input, temp); } } finally { input.clear().writeBytes(temp); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 2eef99bbb..2ef53cd94 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -323,6 +323,11 @@ public class BukkitServerPlayer extends Player { this.plugin.networkManager().sendPacket(this, packet, immediately); } + @Override + public void sendPacket(Object packet, boolean immediately, Runnable sendListener) { + this.plugin.networkManager().sendPacket(this, packet, immediately, sendListener); + } + @Override public void sendCustomPayload(Key channel, byte[] data) { try { @@ -352,8 +357,10 @@ public class BukkitServerPlayer extends Player { try { Object reason = ComponentUtils.adventureToMinecraft(message); Object kickPacket = NetworkReflections.constructor$ClientboundDisconnectPacket.newInstance(reason); - this.sendPacket(kickPacket, true); - this.nettyChannel().disconnect(); + this.sendPacket(kickPacket, false, () -> FastNMS.INSTANCE.method$Connection$disconnect(this.connection(), reason)); + this.nettyChannel().config().setAutoRead(false); + Runnable handleDisconnection = () -> FastNMS.INSTANCE.method$Connection$handleDisconnection(this.connection()); + FastNMS.INSTANCE.method$BlockableEventLoop$scheduleOnMain(handleDisconnection); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to kick " + name(), e); } @@ -364,6 +371,11 @@ public class BukkitServerPlayer extends Player { this.plugin.networkManager().sendPackets(this, packet, immediately); } + @Override + public void sendPackets(List packet, boolean immediately, Runnable sendListener) { + this.plugin.networkManager().sendPackets(this, packet, immediately, sendListener); + } + @Override public void simulatePacket(Object packet) { this.plugin.networkManager().simulatePacket(this, packet); @@ -719,7 +731,8 @@ public class BukkitServerPlayer extends Player { FastNMS.INSTANCE.method$CraftPlayer$getHandle(player) ) ), - packet + packet, + null ); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 9cc7ac42d..956a55571 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -28,6 +28,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void sendPackets(List packet, boolean immediately); + public abstract void sendPackets(List packet, boolean immediately, Runnable sendListener); + public abstract float getDestroyProgress(Object blockState, BlockPos pos); public abstract void setClientSideCanBreakBlock(boolean canBreak); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 9ff316fcf..042413ba9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -27,6 +27,8 @@ public interface NetWorkUser { void sendPacket(Object packet, boolean immediately); + void sendPacket(Object packet, boolean immediately, Runnable sendListener); + void sendCustomPayload(Key channel, byte[] data); void kick(Component message); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java index e24a4ba29..808dd56eb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java @@ -25,14 +25,22 @@ public interface NetworkManager extends Manageable { Player[] onlineUsers(); default void sendPacket(@NotNull NetWorkUser player, Object packet) { - sendPacket(player, packet, false); + sendPacket(player, packet, false, null); } - void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately); + default void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately) { + sendPacket(player, packet, immediately, null); + } + + void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately, Runnable sendListener); default void sendPackets(@NotNull NetWorkUser player, List packet) { - sendPackets(player, packet, false); + sendPackets(player, packet, false, null); } - void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately); + default void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately) { + sendPackets(player, packet, immediately, null); + } + + void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately, Runnable sendListener); } diff --git a/gradle.properties b/gradle.properties index 0975bcb33..837f76854 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.18 -nms_helper_version=1.0.38 +nms_helper_version=1.0.39 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 30599ab105a379d7aea44d05eac2dcda09c7766a Mon Sep 17 00:00:00 2001 From: iqtester <1835ww@gmail.com> Date: Sat, 26 Jul 2025 22:17:03 -0400 Subject: [PATCH 55/83] =?UTF-8?q?=E5=87=91=E6=B4=BB=E7=94=A8=E5=96=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/behavior/BlockItemBehavior.java | 16 ++++++++++++---- .../behavior/DoubleHighBlockItemBehavior.java | 7 +++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index 0fda1036a..faa5afefc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -47,6 +47,8 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -125,15 +127,19 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { // it's just world + pos BlockState previousState = bukkitBlock.getState(); + List revertStates = new ArrayList<>(2); + revertStates.add(previousState); // place custom block - placeBlock(placeLocation, blockStateToPlace); + placeBlock(placeLocation, blockStateToPlace, revertStates); if (player != null) { // call bukkit event BlockPlaceEvent bukkitPlaceEvent = new BlockPlaceEvent(bukkitBlock, previousState, againstBlock, (ItemStack) context.getItem().getItem(), bukkitPlayer, true, context.getHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND); if (EventUtils.fireAndCheckCancel(bukkitPlaceEvent)) { // revert changes - previousState.update(true, false); + for (BlockState state : revertStates) { + state.update(true, false); + } return InteractionResult.FAIL; } @@ -141,7 +147,9 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { CustomBlockPlaceEvent customPlaceEvent = new CustomBlockPlaceEvent(bukkitPlayer, placeLocation.clone(), blockStateToPlace, world.getBlockAt(placeLocation), context.getHand()); if (EventUtils.fireAndCheckCancel(customPlaceEvent)) { // revert changes - previousState.update(true, false); + for (BlockState state : revertStates) { + state.update(true, false); + } return InteractionResult.FAIL; } } @@ -215,7 +223,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { } } - protected boolean placeBlock(Location location, ImmutableBlockState blockState) { + protected boolean placeBlock(Location location, ImmutableBlockState blockState, List revertStates) { return CraftEngineBlocks.place(location, blockState, UpdateOption.UPDATE_ALL_IMMEDIATE, false); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index c9c8949c7..0acf2bfb3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -13,8 +13,10 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.bukkit.Location; +import org.bukkit.block.BlockState; import java.nio.file.Path; +import java.util.List; import java.util.Map; public class DoubleHighBlockItemBehavior extends BlockItemBehavior { @@ -25,14 +27,15 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { } @Override - protected boolean placeBlock(Location location, ImmutableBlockState blockState) { + protected boolean placeBlock(Location location, ImmutableBlockState blockState, List revertState) { Object level = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()); Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()); UpdateOption option = UpdateOption.builder().updateNeighbors().updateClients().updateImmediate().updateKnownShape().build(); Object fluidData = FastNMS.INSTANCE.method$BlockGetter$getFluidState(level, blockPos); Object stateToPlace = fluidData == MFluids.WATER$defaultState ? MBlocks.WATER$defaultState : MBlocks.AIR$defaultState; + revertState.add(location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()).getState()); FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, stateToPlace, option.flags()); - return super.placeBlock(location, blockState); + return super.placeBlock(location, blockState, revertState); } public static class Factory implements ItemBehaviorFactory { From e7dfe03fc1b29c6132541bc5e7c531fa91de27ac Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 27 Jul 2025 21:20:27 +0800 Subject: [PATCH 56/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=BA=93=E7=B1=BB?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitCustomBlock.java | 5 +-- .../classpath/PaperClassPathAppender.java | 41 +++++++++++-------- .../plugin/injector/BlockStateGenerator.java | 4 +- .../plugin/network/PacketConsumers.java | 2 +- gradle.properties | 2 +- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index 95a28e719..14ae935fc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -129,13 +129,12 @@ public final class BukkitCustomBlock extends AbstractCustomBlock { // set block side properties CoreReflections.field$BlockBehaviour$explosionResistance.set(nmsBlock, settings.resistance()); CoreReflections.field$BlockBehaviour$soundType.set(nmsBlock, SoundUtils.toSoundType(settings.sounds())); - // 1.21.2以前要在init cache之前设定 isConditionallyFullOpaque + // init cache + CoreReflections.method$BlockStateBase$initCache.invoke(nmsState); boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion; if (!VersionHelper.isOrAbove1_21_2()) { CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(nmsState, isConditionallyFullOpaque); } - // init cache - CoreReflections.method$BlockStateBase$initCache.invoke(nmsState); // modify cache if (VersionHelper.isOrAbove1_21_2()) { int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(immutableBlockState.vanillaBlockState().handle()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java index 24a89e13d..885b223cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/PaperClassPathAppender.java @@ -18,29 +18,38 @@ public class PaperClassPathAppender implements ClassPathAppender { public static final Field field$PaperPluginClassLoader$libraryLoader = Optional.ofNullable(clazz$PaperPluginClassLoader) .map(it -> ReflectionUtils.getDeclaredField(it, URLClassLoader.class, 0)) .orElse(null); - private final URLClassLoaderAccess classLoaderAccess; + private final URLClassLoaderAccess libraryClassLoaderAccess; + // todo 是否有更好的方法让库被其他插件共享 public PaperClassPathAppender(ClassLoader classLoader) { - // 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); -// } + // 这个类加载器用于加载重定位后的依赖库,这样所有插件都能访问到 + ClassLoader bukkitClassLoader = Bukkit.class.getClassLoader(); + if (bukkitClassLoader instanceof URLClassLoader urlClassLoader) { + this.libraryClassLoaderAccess = URLClassLoaderAccess.create(urlClassLoader); + } else { + // ignite会把Bukkit放置于EmberClassLoader中,获取其父DynamicClassLoader + if (bukkitClassLoader.getClass().getName().equals("space.vectrix.ignite.launch.ember.EmberClassLoader") && bukkitClassLoader.getParent() instanceof URLClassLoader urlClassLoader) { + this.libraryClassLoaderAccess = URLClassLoaderAccess.create(urlClassLoader); + return; + } + try { + // 最次的方案,使用paper自带的classloader去加载依赖,这种情况会发生依赖隔离 + if (clazz$PaperPluginClassLoader != null && clazz$PaperPluginClassLoader.isInstance(classLoader)) { + URLClassLoader libraryClassLoader = (URLClassLoader) field$PaperPluginClassLoader$libraryLoader.get(classLoader); + this.libraryClassLoaderAccess = URLClassLoaderAccess.create(libraryClassLoader); + } else { + throw new IllegalStateException("ClassLoader is not instance of URLClassLoader"); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to instantiate PaperPluginClassLoader", e); + } + } } @Override public void addJarToClasspath(Path file) { try { - this.classLoaderAccess.addURL(file.toUri().toURL()); + this.libraryClassLoaderAccess.addURL(file.toUri().toURL()); } catch (MalformedURLException e) { throw new RuntimeException(e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java index 750a17039..33367919e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java @@ -98,7 +98,7 @@ public final class BlockStateGenerator { if (vec3 == null) return List.of(); Object tool = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.TOOL); - Item item = BukkitItemManager.instance().wrap(tool == null || FastNMS.INSTANCE.method$ItemStack$isEmpty(tool) ? null : FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(tool)); + Item item = BukkitItemManager.instance().wrap(tool == null ? null : FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(tool)); Object optionalPlayer = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.THIS_ENTITY); if (!CoreReflections.clazz$Player.isInstance(optionalPlayer)) { optionalPlayer = null; @@ -107,7 +107,7 @@ public final class BlockStateGenerator { // do not drop if it's not the correct tool BlockSettings settings = state.settings(); if (optionalPlayer != null && settings.requireCorrectTool()) { - if (item == null) return List.of(); + if (item.isEmpty()) return List.of(); if (!settings.isCorrectTool(item.id()) && (!settings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(tool, state.customBlockState().handle()))) { return List.of(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index a7d0e2626..298009399 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1627,7 +1627,7 @@ public class PacketConsumers { } // 必须从网络包层面处理,否则无法获取交互的具体实体 - if (serverPlayer.isSecondaryUseActive() && itemInHand != null) { + if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty()) { // try placing another furniture above it AABB hitBox = furniture.aabbByEntityId(entityId); if (hitBox == null) return; diff --git a/gradle.properties b/gradle.properties index 837f76854..9026ef29a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.6 +project_version=0.0.60.7 config_version=43 lang_version=22 project_group=net.momirealms From 8207753404cb8762d5f8aee9432848362e63cfa2 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 28 Jul 2025 03:52:02 +0800 Subject: [PATCH 57/83] =?UTF-8?q?feat(common):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=8A=B1=E7=AF=AE=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/furniture.yml | 118 +++++++- .../resources/default/configuration/i18n.yml | 2 + .../item/custom/flower_basket_ceiling.json | 285 ++++++++++++++++++ .../item/custom/flower_basket_ground.json | 206 +++++++++++++ .../item/custom/flower_basket_wall.json | 233 ++++++++++++++ .../textures/item/custom/flower_basket.png | Bin 0 -> 2540 bytes .../textures/item/custom/flower_basket_2d.png | Bin 0 -> 547 bytes 7 files changed, 843 insertions(+), 1 deletion(-) create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ceiling.json create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ground.json create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/flower_basket.png create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/flower_basket_2d.png diff --git a/common-files/src/main/resources/resources/default/configuration/furniture.yml b/common-files/src/main/resources/resources/default/configuration/furniture.yml index c28d53cdf..b7d172bd4 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture.yml @@ -132,4 +132,120 @@ items: loot: template: default:loot_table/furniture arguments: - item: default:wooden_chair \ No newline at end of file + item: default:wooden_chair + +items#flower_basket: + default:flower_basket: + material: nether_brick + custom-model-data: 2003 + data: + item-name: + model: + template: default:model/simplified_generated + arguments: + path: minecraft:item/custom/flower_basket_2d + behavior: + type: furniture_item + furniture: default:flower_basket + default:flower_basket_ground: + material: nether_brick + custom-model-data: 2004 + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/flower_basket_ground + default:flower_basket_wall: + material: nether_brick + custom-model-data: 2005 + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/flower_basket_wall + default:flower_basket_ceiling: + material: nether_brick + custom-model-data: 2006 + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/flower_basket_ceiling + +furniture#flower_basket: + default:flower_basket: + settings: + item: default:flower_basket + sounds: + break: minecraft:block.grass.break + place: minecraft:block.grass.place + loot: + template: default:loot_table/furniture + arguments: + item: default:flower_basket + placement: + ground: + rules: + rotation: FOUR + alignment: CENTER + elements: + - item: default:flower_basket_ground + display-transform: NONE + billboard: FIXED + position: 0,0,0 + translation: 0,0.5,0 + hitboxes: + - type: interaction + can-use-item-on: true + can-be-hit-by-projectile: true + blocks-building: true + position: 0,0,0 + width: 0.9 + height: 0.75 + interactive: true + wall: + rules: + rotation: FOUR + alignment: CENTER + elements: + - item: default:flower_basket_wall + display-transform: NONE + billboard: FIXED + position: 0,0,0.2 + translation: 0,0,0 + hitboxes: + - type: interaction + can-use-item-on: true + can-be-hit-by-projectile: true + blocks-building: true + position: 0.215,-0.3,0.23 + width: 0.46 + height: 0.75 + interactive: true + - type: interaction + can-use-item-on: true + can-be-hit-by-projectile: true + blocks-building: true + position: -0.215,-0.3,0.23 + width: 0.46 + height: 0.75 + interactive: true + ceiling: + rules: + rotation: FOUR + alignment: CENTER + elements: + - item: default:flower_basket_ceiling + display-transform: NONE + billboard: FIXED + position: 0,-0.46,0 + translation: 0,0,0 + hitboxes: + - type: interaction + can-use-item-on: true + can-be-hit-by-projectile: true + blocks-building: true + position: 0,-0.9,0 + width: 0.85 + height: 0.9 + interactive: true \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index 815e41006..b032f9c78 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -44,6 +44,7 @@ i18n: item.flame_elytra: Flame Elytra item.pebble: Pebble item.cap: Cap + item.flower_basket: Flower Basket category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -98,6 +99,7 @@ i18n: item.flame_elytra: 烈焰鞘翅 item.pebble: 石子 item.cap: 鸭舌帽 + item.flower_basket: 花篮 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ceiling.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ceiling.json new file mode 100644 index 000000000..31e1ef903 --- /dev/null +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ceiling.json @@ -0,0 +1,285 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "item/custom/flower_basket", + "particle": "item/custom/flower_basket" + }, + "elements": [ + { + "from": [2, 7, -1], + "to": [14, 7, 11], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 7, 5]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "up": {"uv": [0, 16, 4, 12], "texture": "#1"}, + "down": {"uv": [0, 12, 4, 16], "texture": "#1"} + } + }, + { + "from": [2, 4, 12.5], + "to": [14, 16, 12.5], + "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 10, 12.5]}, + "faces": { + "north": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "east": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "south": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "west": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "up": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "down": {"uv": [4, 12, 8, 8], "texture": "#1"} + } + }, + { + "from": [2, 7, 5], + "to": [14, 7, 17], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 7, 11]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "up": {"uv": [0, 12, 4, 16], "texture": "#1"}, + "down": {"uv": [0, 16, 4, 12], "texture": "#1"} + } + }, + { + "from": [-1, 7, 2], + "to": [11, 7, 14], + "rotation": {"angle": -45, "axis": "z", "origin": [5, 7, 8]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "up": {"uv": [4, 16, 0, 12], "rotation": 270, "texture": "#1"}, + "down": {"uv": [0, 16, 4, 12], "rotation": 270, "texture": "#1"} + } + }, + { + "from": [5, 7, 2], + "to": [17, 7, 14], + "rotation": {"angle": 45, "axis": "z", "origin": [11, 7, 8]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "up": {"uv": [4, 12, 0, 16], "rotation": 270, "texture": "#1"}, + "down": {"uv": [0, 12, 4, 16], "rotation": 270, "texture": "#1"} + } + }, + { + "from": [12.5, 4, 2], + "to": [12.5, 16, 14], + "rotation": {"angle": 22.5, "axis": "z", "origin": [12.5, 10, 8]}, + "faces": { + "north": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "east": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "south": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "west": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "up": {"uv": [4, 8, 0, 12], "rotation": 270, "texture": "#1"}, + "down": {"uv": [0, 8, 4, 12], "rotation": 270, "texture": "#1"} + } + }, + { + "from": [3.5, 7.75, 3.5], + "to": [12.5, 9.25, 12.5], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7.1875, 8]}, + "faces": { + "north": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#1"}, + "east": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#1"}, + "south": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#1"}, + "west": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#1"}, + "up": {"uv": [13.5, 12.5, 10.5, 9.5], "texture": "#1"}, + "down": {"uv": [13.5, 12.5, 10.5, 15.5], "texture": "#1"} + } + }, + { + "from": [4.1, 5.35, 4.1], + "to": [11.9, 9.4, 11.9], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 8.6875, 8]}, + "faces": { + "north": {"uv": [13.5, 8.5, 16, 9.75], "texture": "#1"}, + "east": {"uv": [13.5, 8.5, 16, 9.75], "texture": "#1"}, + "south": {"uv": [13.5, 8.5, 16, 9.75], "texture": "#1"}, + "west": {"uv": [13.5, 8.5, 16, 9.75], "texture": "#1"}, + "up": {"uv": [16, 8.5, 13.5, 6], "texture": "#1"}, + "down": {"uv": [16, 3.5, 13.5, 6], "texture": "#1"} + } + }, + { + "from": [8, 1, 0.5], + "to": [8, 13, 15.5], + "rotation": {"angle": 45, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "east": {"uv": [0, 4, 4, 0], "texture": "#1"}, + "south": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "west": {"uv": [4, 4, 0, 0], "texture": "#1"}, + "up": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "down": {"uv": [0, 4, 0, 0], "texture": "#1"} + } + }, + { + "from": [8, 1, 0.5], + "to": [8, 13, 15.5], + "rotation": {"angle": -45, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "east": {"uv": [0, 4, 4, 0], "texture": "#1"}, + "south": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "west": {"uv": [4, 4, 0, 0], "texture": "#1"}, + "up": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "down": {"uv": [0, 4, 0, 0], "texture": "#1"} + } + }, + { + "from": [8, 1, 0.5], + "to": [8, 13, 15.5], + "rotation": {"angle": -45, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "east": {"uv": [4, 4, 8, 0], "texture": "#1"}, + "south": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "west": {"uv": [8, 4, 4, 0], "texture": "#1"}, + "up": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "down": {"uv": [0, 4, 0, 0], "texture": "#1"} + } + }, + { + "from": [8, 1, 0.5], + "to": [8, 13, 15.5], + "rotation": {"angle": 45, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "east": {"uv": [4, 4, 8, 0], "texture": "#1"}, + "south": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "west": {"uv": [8, 4, 4, 0], "texture": "#1"}, + "up": {"uv": [0, 4, 0, 0], "texture": "#1"}, + "down": {"uv": [0, 4, 0, 0], "texture": "#1"} + } + }, + { + "from": [3.5, 4, 2], + "to": [3.5, 16, 14], + "rotation": {"angle": -22.5, "axis": "z", "origin": [3.5, 10, 8]}, + "faces": { + "north": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "east": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "south": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "west": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "up": {"uv": [4, 12, 0, 8], "rotation": 270, "texture": "#1"}, + "down": {"uv": [0, 12, 4, 8], "rotation": 270, "texture": "#1"} + } + }, + { + "from": [-1, 6.25, 2], + "to": [11, 6.25, 14], + "rotation": {"angle": -45, "axis": "z", "origin": [5, 6.25, 8]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "up": {"uv": [10, 8, 6, 4], "rotation": 270, "texture": "#1"}, + "down": {"uv": [6, 8, 10, 4], "rotation": 270, "texture": "#1"} + } + }, + { + "from": [5, 6.25, 2], + "to": [17, 6.25, 14], + "rotation": {"angle": 45, "axis": "z", "origin": [11, 6.25, 8]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "up": {"uv": [10, 4, 6, 8], "rotation": 270, "texture": "#1"}, + "down": {"uv": [6, 4, 10, 8], "rotation": 270, "texture": "#1"} + } + }, + { + "from": [2, 6.25, -1], + "to": [14, 6.25, 11], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 6.25, 5]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#1"}, + "up": {"uv": [6, 8, 10, 4], "texture": "#1"}, + "down": {"uv": [6, 4, 10, 8], "texture": "#1"} + } + }, + { + "from": [2, 6.25, 5], + "to": [14, 6.25, 17], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 6.25, 11]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#1"}, + "up": {"uv": [6, 4, 10, 8], "texture": "#1"}, + "down": {"uv": [6, 8, 10, 4], "texture": "#1"} + } + }, + { + "from": [2, 4, 3.5], + "to": [14, 16, 3.5], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 10, 3.5]}, + "faces": { + "north": {"uv": [8, 8, 4, 12], "texture": "#1"}, + "east": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "south": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "west": {"uv": [4, 8, 8, 12], "texture": "#1"}, + "up": {"uv": [4, 12, 8, 8], "texture": "#1"}, + "down": {"uv": [4, 8, 8, 12], "texture": "#1"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [60, -34, 0], + "translation": [-0.5, 3, 1], + "scale": [0.5, 0.5, 0.5] + }, + "thirdperson_lefthand": { + "rotation": [60, -34, 0], + "translation": [-0.5, 3, 1], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [3.5, 0, 0] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [3.5, 0, 0] + }, + "ground": { + "translation": [0, 3.25, 0], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [25, 135, 0], + "translation": [0, -0.25, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [90, 0, 0], + "translation": [0, 0, -15], + "scale": [2, 2, 2] + } + }, + "groups": [ + { + "name": "bone3", + "origin": [-3, 4, -3], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ground.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ground.json new file mode 100644 index 000000000..38d9eba22 --- /dev/null +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ground.json @@ -0,0 +1,206 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "item/custom/flower_basket" + }, + "elements": [ + { + "from": [2, 6.75, -1], + "to": [14, 6.75, 11], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 6.75, 5]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [0, 16, 4, 12], "texture": "#0"}, + "down": {"uv": [0, 12, 4, 16], "texture": "#0"} + } + }, + { + "from": [2, 8.25, -1], + "to": [14, 8.25, 11], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 8.25, 5]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [0, 12, 4, 8], "texture": "#0"}, + "down": {"uv": [0, 8, 4, 12], "texture": "#0"} + } + }, + { + "from": [2, 8.25, 5], + "to": [14, 8.25, 17], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 8.25, 11]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [0, 8, 4, 12], "texture": "#0"}, + "down": {"uv": [0, 12, 4, 8], "texture": "#0"} + } + }, + { + "from": [2, 6.75, 5], + "to": [14, 6.75, 17], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 6.75, 11]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [0, 12, 4, 16], "texture": "#0"}, + "down": {"uv": [0, 16, 4, 12], "texture": "#0"} + } + }, + { + "from": [-1, 6.75, 2], + "to": [11, 6.75, 14], + "rotation": {"angle": 45, "axis": "z", "origin": [5, 6.75, 8]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [4, 16, 0, 12], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 16, 4, 12], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [5, 6.75, 2], + "to": [17, 6.75, 14], + "rotation": {"angle": -45, "axis": "z", "origin": [11, 6.75, 8]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [4, 12, 0, 16], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 12, 4, 16], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [5, 8.25, 2], + "to": [17, 8.25, 14], + "rotation": {"angle": -45, "axis": "z", "origin": [11, 8.25, 8]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [4, 8, 0, 12], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 8, 4, 12], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [-1, 8.25, 2], + "to": [11, 8.25, 14], + "rotation": {"angle": 45, "axis": "z", "origin": [5, 8.25, 8]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [4, 12, 0, 8], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 12, 4, 8], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [3.5, 3.75, 3.5], + "to": [12.5, 5.25, 12.5], + "rotation": {"angle": 0, "axis": "y", "origin": [4.25, 3.75, 4.25]}, + "faces": { + "north": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#0"}, + "east": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#0"}, + "south": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#0"}, + "west": {"uv": [10.5, 15.5, 13.5, 16], "texture": "#0"}, + "up": {"uv": [13.5, 12.5, 10.5, 9.5], "texture": "#0"}, + "down": {"uv": [13.5, 12.5, 10.5, 15.5], "texture": "#0"} + } + }, + { + "from": [4.25, 0, 4.25], + "to": [11.75, 3.75, 11.75], + "rotation": {"angle": 0, "axis": "y", "origin": [5, 0, 5]}, + "faces": { + "north": {"uv": [13.5, 14.75, 16, 16], "texture": "#0"}, + "east": {"uv": [13.5, 14.75, 16, 16], "texture": "#0"}, + "south": {"uv": [13.5, 14.75, 16, 16], "texture": "#0"}, + "west": {"uv": [13.5, 14.75, 16, 16], "texture": "#0"}, + "up": {"uv": [16, 14.75, 13.5, 12.25], "texture": "#0"}, + "down": {"uv": [16, 9.75, 13.5, 12.25], "texture": "#0"} + } + }, + { + "from": [8, 0, 0.5], + "to": [8, 12, 15.5], + "rotation": {"angle": 45, "axis": "y", "origin": [8, 6, 8]}, + "faces": { + "north": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 4], "texture": "#0"}, + "south": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 4], "texture": "#0"}, + "up": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "down": {"uv": [0, 0, 0, 4], "texture": "#0"} + } + }, + { + "from": [8, 0, 0.5], + "to": [8, 12, 15.5], + "rotation": {"angle": -45, "axis": "y", "origin": [8, 6, 8]}, + "faces": { + "north": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 4], "texture": "#0"}, + "south": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 4], "texture": "#0"}, + "up": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "down": {"uv": [0, 0, 0, 4], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [60, -34, 0], + "translation": [-0.5, 3, 1], + "scale": [0.5, 0.5, 0.5] + }, + "thirdperson_lefthand": { + "rotation": [60, -34, 0], + "translation": [-0.5, 3, 1], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [3.5, 0, 0] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [3.5, 0, 0] + }, + "ground": { + "translation": [0, 3.25, 0], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [25, -40, 0], + "translation": [-0.25, 2, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0, -16], + "scale": [2, 2, 2] + } + }, + "groups": [ + { + "name": "bone", + "origin": [-3, 0, -3], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json new file mode 100644 index 000000000..b627c0756 --- /dev/null +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json @@ -0,0 +1,233 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "0": "item/custom/flower_basket" + }, + "elements": [ + { + "from": [-1, 11.5625, 4.43375], + "to": [11, 11.5625, 13.43375], + "rotation": {"angle": 45, "axis": "z", "origin": [5, 11.5625, 7.43375]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [3, 4, 0, 8], "rotation": 90, "texture": "#0"}, + "down": {"uv": [3, 8, 0, 4], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [-1, 10.0625, 4.43375], + "to": [11, 10.0625, 13.43375], + "rotation": {"angle": 45, "axis": "z", "origin": [5, 10.0625, 7.43375]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [6, 4, 3, 8], "rotation": 90, "texture": "#0"}, + "down": {"uv": [6, 8, 3, 4], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [5, 11.5625, 4.43375], + "to": [17, 11.5625, 13.43375], + "rotation": {"angle": -45, "axis": "z", "origin": [11, 11.5625, 7.43375]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [3, 8, 0, 4], "rotation": 90, "texture": "#0"}, + "down": {"uv": [3, 4, 0, 8], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [5, 10.0625, 4.43375], + "to": [17, 10.0625, 13.43375], + "rotation": {"angle": -45, "axis": "z", "origin": [11, 10.0625, 7.43375]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [6, 8, 3, 4], "rotation": 90, "texture": "#0"}, + "down": {"uv": [6, 4, 3, 8], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [2, 10.0625, 4.43375], + "to": [14, 10.0625, 16.43375], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 10.0625, 10.43375]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [4, 12, 0, 16], "texture": "#0"}, + "down": {"uv": [0, 12, 4, 16], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [2, 10.0625, 1.43375], + "to": [14, 10.0625, 13.43375], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 10.0625, 7.43375]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [4, 16, 0, 12], "texture": "#0"}, + "down": {"uv": [0, 16, 4, 12], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [2, 11.5625, 2.18375], + "to": [14, 11.5625, 14.18375], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 11.5625, 8.18375]}, + "faces": { + "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, + "up": {"uv": [4, 12, 0, 8], "texture": "#0"}, + "down": {"uv": [0, 12, 4, 8], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [2, 11.5625, 3.68375], + "to": [14, 11.5625, 15.68375], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 11.5625, 9.68375]}, + "faces": { + "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "up": {"uv": [4, 8, 0, 12], "texture": "#0"}, + "down": {"uv": [0, 8, 4, 12], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [3.5, 7.0625, 5.93375], + "to": [12.5, 8.5625, 11.93375], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 7.43375]}, + "faces": { + "north": {"uv": [13.5, 15.5, 10.5, 16], "texture": "#0"}, + "east": {"uv": [9, 15.5, 7, 16], "texture": "#0"}, + "south": {"uv": [13.5, 15.5, 10.5, 16], "texture": "#0"}, + "west": {"uv": [9, 15.5, 7, 16], "texture": "#0"}, + "up": {"uv": [11.5, 6.5, 13.5, 3.5], "rotation": 90, "texture": "#0"}, + "down": {"uv": [11.5, 6.5, 13.5, 9.5], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [4.25, 3.3125, 6.68375], + "to": [11.75, 7.0625, 11.18375], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 7.43375]}, + "faces": { + "north": {"uv": [16, 14.75, 13.5, 16], "texture": "#0"}, + "east": {"uv": [10.5, 14.75, 9, 16], "texture": "#0"}, + "south": {"uv": [16, 14.75, 13.5, 16], "texture": "#0"}, + "west": {"uv": [10.5, 14.75, 9, 16], "texture": "#0"}, + "up": {"uv": [8, 14.75, 10.5, 12.25], "rotation": 90, "texture": "#0"}, + "down": {"uv": [9, 9.75, 10.5, 12.25], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [4.1, 3.1625, 6.53375], + "to": [11.9, 7.2125, 11.33375], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 7.43375]}, + "faces": { + "north": {"uv": [16, 8.5, 13.5, 9.75], "texture": "#0"}, + "east": {"uv": [16, 8.5, 14.5, 9.75], "texture": "#0"}, + "south": {"uv": [16, 8.5, 13.5, 9.75], "texture": "#0"}, + "west": {"uv": [14.5, 8.5, 16, 9.75], "texture": "#0"}, + "up": {"uv": [13.5, 8.5, 16, 6], "rotation": 90, "texture": "#0"}, + "down": {"uv": [15, 3.5, 13.5, 6], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [0.5, 3.3125, 8.93375], + "to": [15.5, 15.3125, 8.93375], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 9.3125, 8.93375]}, + "faces": { + "north": {"uv": [4, 0, 0, 4], "texture": "#0"}, + "east": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 4], "texture": "#0"}, + "west": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "up": {"uv": [0, 0, 0, 4], "rotation": 90, "texture": "#0"}, + "down": {"uv": [0, 0, 0, 4], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [0.5, 3.3125, 8.93375], + "to": [15.5, 15.3125, 8.93375], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 9.3125, 8.93375]}, + "faces": { + "north": {"uv": [4, 0, 0, 4], "texture": "#0"}, + "east": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "south": {"uv": [0, 0, 4, 4], "texture": "#0"}, + "west": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "up": {"uv": [0, 0, 0, 4], "rotation": 90, "texture": "#0"}, + "down": {"uv": [0, 0, 0, 4], "rotation": 270, "texture": "#0"} + } + }, + { + "from": [5, 3.3125, 4.44125], + "to": [11, 5.5625, 6.69125], + "rotation": {"angle": 0, "axis": "y", "origin": [10.25, 3.3125, 5.93375]}, + "faces": { + "north": {"uv": [16, 0, 14, 0.75], "texture": "#0"}, + "east": {"uv": [14, 2.75, 13.25, 3.5], "texture": "#0"}, + "south": {"uv": [16, 0.75, 14, 1.5], "texture": "#0"}, + "west": {"uv": [13.25, 2.75, 14, 3.5], "texture": "#0"}, + "up": {"uv": [13.25, 0, 12.5, 2], "rotation": 90, "texture": "#0"}, + "down": {"uv": [14, 0, 13.25, 2], "rotation": 270, "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [60, -34, 0], + "translation": [-0.5, 3, 1], + "scale": [0.5, 0.5, 0.5] + }, + "thirdperson_lefthand": { + "rotation": [60, -34, 0], + "translation": [-0.5, 3, 1], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [3.5, 0, 0] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [3.5, 0, 0] + }, + "ground": { + "translation": [0, 3.25, 0], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [25, 135, 0], + "translation": [-0.25, 2, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0, -16], + "scale": [2, 2, 2] + } + }, + "groups": [ + { + "name": "bone2", + "origin": [-5, 5.3125, -4.43375], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/flower_basket.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/flower_basket.png new file mode 100644 index 0000000000000000000000000000000000000000..d7a8f86ba19eb57489775afdc3916e4a0069865d GIT binary patch literal 2540 zcmVPx;rb$FWRCt`#TVHHb*BSpE&nd`tjqNNoV8|jMBUFxZLg%%0%u#HWq5qU?|v}sx)6qI;E?G{!6X|_hfsbYz+#90D0t?T;c&x}VF zD`yY(xw*bR_xj#z$Aq60`QCHSIrn_u`ObI0e<3J=g`ODw+B^G6seVry{y-}oyM3!* zou1}qTK2@TOJj7QCq@C_-IssIop2!1q5DOlu)qApN#GB(7R|?Nlfzu9!!JKSiBtdm zEdb!#d%F<3z^NXAgh5ht|_kG5FD$BbS*D0aobBtfk}EZ@yZpk z^FXA74n#WWP~SND)}Px5+kNx(oduG>2+_OX8p?5FX$b-ez!Uyy~K zn5YvNjEZrk^?(tW0KhlgMfShuC$HZ5DQrh;F&|H3?AA)rB12(6eY@*N_{W1Q;siHG z`Dd>bqUR#y{&cniB;>GThuzRPQ3nh}I%s>qg15}45T9GeP~SKi>KiBVxpg2f2>`$( zK{|;Majx_c;6X_-s>0LnrQL%qlr7NH@1^WdZH$rk=wICy#PRb-RGFg$PrsLLnJ+^GBID-h#g@R)dA$|{rg-3)k|o2ft0N;Q238+$!8 zlUl>f#b|+Ii(k7(Jxu1HTvE3K9CmwYZ_p?z zO|Tq^WCkvm4ZsQ((^)t_n*j3nDPbMq@Cf0>2pIf-%?<}hjKvt_Ys&t3q)QQs~cs(%&$kVvfPn&XKuK<-iUJWMUvcK0d(ATH#T;YvC; zgoWHVRCH)8h@_Io#s>T2oU-;t8By6A7 zitP(MF^cQJFcyvmy!b4R;X?>tB$iwnqP;GVue)1K_2v zi(21RZ@~`(yLHV`#DMO>7CO{7PMFdv74vs@9;A$TCIwPYa0b=2G$^KySIDl~I3 zN~9t`b1_OXsWm7mMfX0FNLe0KRfk%JSFRf%Bbr_F+BOT7(g78RQaGy8;jl_E zpyG#3DHu6+`xY^jso7*y)E8j(w^G=fJyWyLwgk%Y*VV*)D;|L&2`I;3FO~3c*zHx5 z0DqvBI_!4XYd2i)rBtfuUSvSI{yHN}tt4fBVII+`DOE2`E0RK1ai^0)7GsfHgatl% zeOSO$WI!eS^-?0fV~5@FG5F~0cPRj*gmtk^EiZ5}G6RQQxn_VpQzeSk3>kGICV2fqDmK3sLn{?;rTpbYB9w_Do z}qbLFM@w8}@^Lzm{bPu-B>4%Te91I`gV!W5{VVyg`KJrz?f3!G{YpV2xDNxvm(e+yD#++Lb{#n?p1TL3Nb6QNQO9~hO*)Fm(f5Q7dVG@A+&iPvlxyz1^ zoM~FdD;+B(jV*`UX(=GsW+kW(zQG;C#9w|43X~wP=viI|EPXEhLa<$yDo@^c`Sbbs z#u1S&R=!(o(YbGa;VvuX1?m#T^YGra<-9U2h7j_G4*;x9j>6@#!Db~`NmES61YL&E zmScbtq^58pnSrZr<4Ysv1!N^MTIPLf3M7Vaeu@LG4cnggsY@g?NF+D%16uIZFyMg8 zjx!lSQ{S^Lr{;N|x(X3XZ4EaKXEZgZ$^fHD&uXKbyrkk0V1>*d-(C{0nZfiVkx8v- zYSRiu31GystPhWPmPvY=!Igl^ZKr92-3#BzE|GX%aHLxKJ1wx())<4$?8}1_UYxhWFuZO`Q6eG)0A^3WmwtSE363TU8o&AsX1@F%0O0W9=P-Ul zfTPJGPX5U!|AC{)g2m~K;R^Fo=xnR!wlm95Nz~=-oo)4^S*(PVunu$dT!b)f&WaWm zr!$z&i~DLaR|BxE-%GdE)gXEPx$-AP12R5*>bl1*z9VHAa*i9z~B2ydN?DMXD{gV^ArL6jOK$;JvUTu4JjH%g(> zU4KAu(QTnxHwAHHe?k$8jT=j=Vk;z` zTb%-c#n+pxZPg^l3Dd(V4kS)e&Q-a7^(a%9QmAvQlyg$$2G-|D~<7G|XKlhN2|p1VWrzFi_S*aJZ5%?`UGf>64SrZ-sZ`%YnDQ*tB#P~eWf@3hAEh6*=`I1Iq-H`S(*3wK7JS-!NJ>P!C%gV Date: Mon, 28 Jul 2025 03:56:03 +0800 Subject: [PATCH 58/83] =?UTF-8?q?feat(common):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=8A=B1=E7=AF=AE=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/resources/default/configuration/categories.yml | 1 + .../craftengine/core/pack/AbstractPackManager.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 8bbcc8cf8..10ef8b0f2 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -57,6 +57,7 @@ categories: - default:bench - default:table_lamp - default:wooden_chair + - default:flower_basket default:misc: name: hidden: true diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 7f7a20441..f8bb24094 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -497,6 +497,11 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/table_lamp.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/wooden_chair.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/bench.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ceiling.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_ground.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flower_basket.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flower_basket_2d.png"); // tooltip plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_background.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_background.png.mcmeta"); From 9b1ddb07e24a8c89f9a89c6bddfe280cf247b33b Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 28 Jul 2025 09:11:25 +0800 Subject: [PATCH 59/83] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E5=8F=8D=E5=B0=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/reflection/minecraft/CoreReflections.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 77076e777..d0eb6fa8c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3746,7 +3746,7 @@ public final class CoreReflections { .orElse( null); public static final Field field$ServerCommonPacketListenerImpl$closed = MiscUtils.requireNonNullIf( - ReflectionUtils.getDeclaredField(clazz$ServerCommonPacketListenerImpl, boolean.class, VersionHelper.isOrAbove1_21_6() ? 1 : 2), + ReflectionUtils.getDeclaredField(clazz$ServerCommonPacketListenerImpl, "closed", "n"), VersionHelper.isOrAbove1_20_5() ); From ce03f799a7708427aa761126c9022f3fc37c4ed5 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 28 Jul 2025 09:30:59 +0800 Subject: [PATCH 60/83] =?UTF-8?q?refactor(furniture):=20=E4=B8=8D=E9=99=90?= =?UTF-8?q?=E5=88=B6=E6=94=BE=E7=BD=AE=E4=BD=8D=E7=BD=AE=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E7=81=B5=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/resources/default/configuration/furniture.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common-files/src/main/resources/resources/default/configuration/furniture.yml b/common-files/src/main/resources/resources/default/configuration/furniture.yml index b7d172bd4..c1c8402fe 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture.yml @@ -187,7 +187,7 @@ furniture#flower_basket: ground: rules: rotation: FOUR - alignment: CENTER + alignment: ANY elements: - item: default:flower_basket_ground display-transform: NONE @@ -206,7 +206,7 @@ furniture#flower_basket: wall: rules: rotation: FOUR - alignment: CENTER + alignment: ANY elements: - item: default:flower_basket_wall display-transform: NONE @@ -233,7 +233,7 @@ furniture#flower_basket: ceiling: rules: rotation: FOUR - alignment: CENTER + alignment: ANY elements: - item: default:flower_basket_ceiling display-transform: NONE From 29b5d4880910054098fa4196655db40bcfa8f974 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 28 Jul 2025 20:30:58 +0800 Subject: [PATCH 61/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=89=A9=E5=93=81?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=97=A0=E6=95=88=E4=B8=8D=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- .../bukkit/item/BukkitItemManager.java | 9 +++----- .../default/configuration/furniture.yml | 21 +++++++------------ 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 4c6e8fa0b..535c1c54d 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.59") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.59") + compileOnly("net.momirealms:craft-engine-core:0.0.61") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.61") } ``` \ No newline at end of file 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 64e8735e5..9a060037f 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 @@ -12,10 +12,7 @@ import net.momirealms.craftengine.bukkit.item.listener.DebugStickListener; import net.momirealms.craftengine.bukkit.item.listener.ItemEventListener; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*; import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -380,10 +377,10 @@ public class BukkitItemManager extends AbstractItemManager { protected CustomItem.Builder createPlatformItemBuilder(UniqueKey id, Key materialId, Key clientBoundMaterialId) { Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(materialId)); Object clientBoundItem = materialId == clientBoundMaterialId ? item : FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(clientBoundMaterialId)); - if (item == null) { + if (item == MItems.AIR) { throw new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString()); } - if (clientBoundItem == null) { + if (clientBoundItem == MItems.AIR) { throw new LocalizedResourceConfigException("warning.config.item.invalid_material", clientBoundMaterialId.toString()); } return BukkitCustomItem.builder(item, clientBoundItem) diff --git a/common-files/src/main/resources/resources/default/configuration/furniture.yml b/common-files/src/main/resources/resources/default/configuration/furniture.yml index c1c8402fe..23212868d 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture.yml @@ -150,24 +150,18 @@ items#flower_basket: default:flower_basket_ground: material: nether_brick custom-model-data: 2004 - data: - item-name: model: type: minecraft:model path: minecraft:item/custom/flower_basket_ground default:flower_basket_wall: material: nether_brick custom-model-data: 2005 - data: - item-name: model: type: minecraft:model path: minecraft:item/custom/flower_basket_wall default:flower_basket_ceiling: material: nether_brick custom-model-data: 2006 - data: - item-name: model: type: minecraft:model path: minecraft:item/custom/flower_basket_ceiling @@ -186,7 +180,7 @@ furniture#flower_basket: placement: ground: rules: - rotation: FOUR + rotation: ANY alignment: ANY elements: - item: default:flower_basket_ground @@ -200,12 +194,11 @@ furniture#flower_basket: can-be-hit-by-projectile: true blocks-building: true position: 0,0,0 - width: 0.9 - height: 0.75 + width: 0.7 + height: 0.5 interactive: true wall: rules: - rotation: FOUR alignment: ANY elements: - item: default:flower_basket_wall @@ -232,7 +225,7 @@ furniture#flower_basket: interactive: true ceiling: rules: - rotation: FOUR + rotation: ANY alignment: ANY elements: - item: default:flower_basket_ceiling @@ -245,7 +238,7 @@ furniture#flower_basket: can-use-item-on: true can-be-hit-by-projectile: true blocks-building: true - position: 0,-0.9,0 - width: 0.85 - height: 0.9 + position: 0,-0.7,0 + width: 0.7 + height: 0.7 interactive: true \ No newline at end of file From 4947b473103c06e64b6024425167710bbe514e02 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 30 Jul 2025 15:51:45 +0800 Subject: [PATCH 62/83] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=85=8D=E6=96=B9?= =?UTF-8?q?=E5=89=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/BukkitFurnitureElement.java | 3 +- .../item/factory/BukkitItemFactory.java | 20 ++- .../factory/ComponentItemFactory1_20_5.java | 11 +- .../item/factory/UniversalItemFactory.java | 9 +- .../item/recipe/BukkitRecipeManager.java | 3 +- .../item/recipe/RecipeEventListener.java | 82 ++++++--- .../reflection/minecraft/CoreReflections.java | 7 + .../bukkit/util/InteractUtils.java | 5 +- .../entity/furniture/FurnitureExtraData.java | 9 +- .../craftengine/core/item/AbstractItem.java | 15 +- .../core/item/AbstractItemManager.java | 4 +- .../craftengine/core/item/Item.java | 10 +- .../craftengine/core/item/ItemFactory.java | 9 +- .../craftengine/core/item/ItemKeys.java | 18 +- .../craftengine/core/item/ItemSettings.java | 28 ++- .../core/item/modifier/DyedColorModifier.java | 5 +- .../core/item/recipe/CustomDyeRecipe.java | 159 ++++++++++++++++++ .../core/item/recipe/RecipeTypes.java | 1 + .../core/item/recipe/input/CraftingInput.java | 9 +- .../context/function/ParticleFunction.java | 10 +- .../craftengine/core/util/Color.java | 91 +++++++--- gradle.properties | 4 +- 22 files changed, 416 insertions(+), 96 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java index f108d5e2a..b82f164f0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureElement; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.data.FireworkExplosion; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Material; @@ -65,7 +66,7 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement { } } - private synchronized List getCachedValues(@Nullable Integer color, int @Nullable [] colors) { + private synchronized List getCachedValues(@Nullable Color color, int @Nullable [] colors) { List cachedValues = new ArrayList<>(this.commonValues); Item item = BukkitItemManager.instance().createWrappedItem(item(), null); if (item == null) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 0c5ee3b3c..e0296b3e2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.StringUtils; import net.momirealms.craftengine.core.util.UniqueKey; @@ -111,11 +112,20 @@ public abstract class BukkitItemFactory> extend protected boolean is(W item, Key itemTag) { Object literalObject = item.getLiteralObject(); Object tag = ItemTags.getOrCreate(itemTag); - try { - return (boolean) CoreReflections.method$ItemStack$isTag.invoke(literalObject, tag); - } catch (ReflectiveOperationException e) { - return false; - } + return FastNMS.INSTANCE.method$ItemStack$is(literalObject, tag); + } + + @Override + protected boolean isDyeItem(W item) { + return CoreReflections.clazz$DyeItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject())); + } + + @Override + protected Optional dyeColor(W item) { + Object itemStack = item.getLiteralObject(); + Object dyeItem = FastNMS.INSTANCE.method$ItemStack$getItem(itemStack); + if (!CoreReflections.clazz$DyeItem.isInstance(dyeItem)) return Optional.empty(); + return Optional.of(Color.fromDecimal(FastNMS.INSTANCE.method$DyeColor$getTextureDiffuseColor(FastNMS.INSTANCE.method$DyeItem$getDyeColor(dyeItem)))); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 9abbd8a16..ae6cf7e17 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.data.Trim; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.sparrow.nbt.CompoundTag; @@ -386,23 +387,23 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory dyedColor(ComponentItemWrapper item) { + protected Optional dyedColor(ComponentItemWrapper item) { if (!item.hasComponent(ComponentTypes.DYED_COLOR)) return Optional.empty(); Object javaObj = getJavaComponent(item, ComponentTypes.DYED_COLOR); if (javaObj instanceof Integer integer) { - return Optional.of(integer); + return Optional.of(Color.fromDecimal(integer)); } else if (javaObj instanceof Map map) { - return Optional.of((int) map.get("rgb")); + return Optional.of(Color.fromDecimal((int) map.get("rgb"))); } return Optional.empty(); } @Override - protected void dyedColor(ComponentItemWrapper item, Integer color) { + protected void dyedColor(ComponentItemWrapper item, Color color) { if (color == null) { item.resetComponent(ComponentTypes.DYED_COLOR); } else { - item.setJavaComponent(ComponentTypes.DYED_COLOR, color); + item.setJavaComponent(ComponentTypes.DYED_COLOR, color.color()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index 1d77a5ef4..c8437d089 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.data.Trim; import net.momirealms.craftengine.core.item.modifier.IdModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.SkullUtils; import net.momirealms.sparrow.nbt.Tag; @@ -169,17 +170,17 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected Optional dyedColor(LegacyItemWrapper item) { + protected Optional dyedColor(LegacyItemWrapper item) { if (!item.hasTag("display", "color")) return Optional.empty(); - return Optional.of(item.getJavaTag("display", "color")); + return Optional.of(Color.fromDecimal(item.getJavaTag("display", "color"))); } @Override - protected void dyedColor(LegacyItemWrapper item, Integer color) { + protected void dyedColor(LegacyItemWrapper item, Color color) { if (color == null) { item.remove("display", "color"); } else { - item.setTag(color, "display", "color"); + item.setTag(color.color(), "display", "color"); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 953f220fe..7538a9272 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -46,6 +46,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { private static final Map>> MIXED_RECIPE_CONVERTORS = new HashMap<>(); private static final List injectedIngredients = new ArrayList<>(); private static final IdentityHashMap, Object> CE_RECIPE_2_NMS_HOLDER = new IdentityHashMap<>(); + public static final CustomDyeRecipe DYE_RECIPE = new CustomDyeRecipe<>(); private static Object nmsRecipeManager; private static void registerNMSSmithingRecipe(Object recipe) { @@ -541,7 +542,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { Optional nmsRecipe = getOptionalNMSRecipe(entry.getKey()); nmsRecipe.ifPresent(o -> CE_RECIPE_2_NMS_HOLDER.put(entry.getValue(), o)); } - + CE_RECIPE_2_NMS_HOLDER.put(DYE_RECIPE, getOptionalNMSRecipe(CustomDyeRecipe.ID).orElseThrow(() -> new IllegalStateException("DyeRecipe not found"))); super.isReloading = false; } catch (Exception e) { this.plugin.logger().warn("Failed to run delayed recipe tasks", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 2f1da0cb7..4f5d13d3f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -745,13 +745,15 @@ public class RecipeEventListener implements Listener { int newItemDamage = Math.max(0, newItem.maxDamage() - remainingDurability); newItem.damage(newItemDamage); inventory.setResult(newItem.getItem()); - } else if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe) || CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) { + } else if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) { + handlePossibleDyeRecipe(event, false); + } else if (CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) { ItemStack[] itemStacks = inventory.getMatrix(); for (ItemStack itemStack : itemStacks) { if (itemStack == null) continue; Item item = plugin.itemManager().wrap(itemStack); Optional> optionalCustomItem = item.getCustomItem(); - if (optionalCustomItem.isPresent() && !optionalCustomItem.get().settings().dyeable()) { + if (optionalCustomItem.isPresent() && optionalCustomItem.get().settings().dyeable() == Tristate.FALSE) { inventory.setResult(null); return; } @@ -824,16 +826,37 @@ public class RecipeEventListener implements Listener { } } + @EventHandler(ignoreCancelled = true) + public void onDyeRecipe(PrepareItemCraftEvent event) { + org.bukkit.inventory.Recipe recipe = event.getRecipe(); + if (recipe != null) { + return; + } + handlePossibleDyeRecipe(event, true); + } + + private void handlePossibleDyeRecipe(PrepareItemCraftEvent event, boolean correct) { + // dye recipe + CraftingInventory inventory = event.getInventory(); + CraftingInput input = getCraftingInput(inventory); + if (input == null) return; + if (BukkitRecipeManager.DYE_RECIPE.matches(input)) { + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); + event.getInventory().setResult(BukkitRecipeManager.DYE_RECIPE.assemble(input, ItemBuildContext.of(this.plugin.adapt(player)))); + if (correct) { + correctCraftingRecipeUsed(inventory, BukkitRecipeManager.DYE_RECIPE); + } + } + } + @EventHandler(ignoreCancelled = true) public void onCraftingRecipe(PrepareItemCraftEvent event) { if (!Config.enableRecipeSystem()) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); - if (recipe == null) - return; // we only handle shaped and shapeless recipes - boolean shapeless = event.getRecipe() instanceof ShapelessRecipe; - boolean shaped = event.getRecipe() instanceof ShapedRecipe; + boolean shapeless = recipe instanceof ShapelessRecipe; + boolean shaped = recipe instanceof ShapedRecipe; if (!shaped && !shapeless) return; CraftingRecipe craftingRecipe = (CraftingRecipe) recipe; @@ -846,24 +869,10 @@ public class RecipeEventListener implements Listener { } CraftingInventory inventory = event.getInventory(); - ItemStack[] ingredients = inventory.getMatrix(); - - List> uniqueIdItems = new ArrayList<>(); - for (ItemStack itemStack : ingredients) { - uniqueIdItems.add(getUniqueIdItem(itemStack)); - } - - CraftingInput input; - if (ingredients.length == 9) { - input = CraftingInput.of(3, 3, uniqueIdItems); - } else if (ingredients.length == 4) { - input = CraftingInput.of(2, 2, uniqueIdItems); - } else { - return; - } + CraftingInput input = getCraftingInput(inventory); + if (input == null) return; Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); Key lastRecipe = serverPlayer.lastUsedRecipe(); @@ -889,17 +898,34 @@ public class RecipeEventListener implements Listener { inventory.setResult(null); } + private CraftingInput getCraftingInput(CraftingInventory inventory) { + ItemStack[] ingredients = inventory.getMatrix(); + + List> uniqueIdItems = new ArrayList<>(); + for (ItemStack itemStack : ingredients) { + uniqueIdItems.add(getUniqueIdItem(itemStack)); + } + + CraftingInput input; + if (ingredients.length == 9) { + input = CraftingInput.of(3, 3, uniqueIdItems); + } else if (ingredients.length == 4) { + input = CraftingInput.of(2, 2, uniqueIdItems); + } else { + return null; + } + return input; + } + private void correctCraftingRecipeUsed(CraftingInventory inventory, Recipe recipe) { Object holderOrRecipe = this.recipeManager.nmsRecipeHolderByRecipe(recipe); if (holderOrRecipe == null) { return; } - try { - Object resultInventory = CraftBukkitReflections.field$CraftInventoryCrafting$resultInventory.get(inventory); - CoreReflections.field$ResultContainer$recipeUsed.set(resultInventory, holderOrRecipe); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to correct used recipe", e); - } + Object resultInventory = FastNMS.INSTANCE.method$CraftInventoryCrafting$getResultInventory(inventory); + FastNMS.INSTANCE.method$ResultContainer$setRecipeUsed(resultInventory, holderOrRecipe); + Object matrixInventory = FastNMS.INSTANCE.method$CraftInventoryCrafting$getMatrixInventory(inventory); + FastNMS.INSTANCE.method$CraftingContainer$setCurrentRecipe(matrixInventory, holderOrRecipe); } @EventHandler(ignoreCancelled = true) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index d0eb6fa8c..76514f5de 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3896,4 +3896,11 @@ public final class CoreReflections { throw new ReflectionInitException("Failed to initialize SnowLayerBlock$LAYERS", e); } } + + public static final Class clazz$DyeItem = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.ItemDye", + "world.item.DyeItem" + ) + ); } 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 c63b370d0..b9f6c5556 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 @@ -14,7 +14,10 @@ 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.*; +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.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.GameMode; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java index c7c5704e9..72587f2a1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.logger.Debugger; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.NBT; @@ -49,8 +50,8 @@ public class FurnitureExtraData { return Optional.empty(); } - public Optional dyedColor() { - if (this.data.containsKey(DYED_COLOR)) return Optional.of(this.data.getInt(DYED_COLOR)); + public Optional dyedColor() { + if (this.data.containsKey(DYED_COLOR)) return Optional.of(Color.fromDecimal(this.data.getInt(DYED_COLOR))); return Optional.empty(); } @@ -92,9 +93,9 @@ public class FurnitureExtraData { return this; } - public Builder dyedColor(Integer color) { + public Builder dyedColor(Color color) { if (color == null) return this; - this.data.putInt(DYED_COLOR, color); + this.data.putInt(DYED_COLOR, color.color()); return this; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 74f5d96a3..33170ded2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.data.Trim; import net.momirealms.craftengine.core.item.setting.EquipmentData; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; @@ -107,13 +108,13 @@ public class AbstractItem, I> implements Item { } @Override - public Item dyedColor(Integer data) { + public Item dyedColor(Color data) { this.factory.dyedColor(this.item, data); return this; } @Override - public Optional dyedColor() { + public Optional dyedColor() { return this.factory.dyedColor(this.item); } @@ -473,4 +474,14 @@ public class AbstractItem, I> implements Item { public void shrink(int amount) { this.item.shrink(amount); } + + @Override + public boolean isDyeItem() { + return this.factory.isDyeItem(this.item); + } + + @Override + public Optional dyeColor() { + return this.factory.dyeColor(this.item); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 2635e6d7d..79ee3ad6a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -548,10 +548,10 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl }, "dynamic-lore"); registerDataType((obj) -> { if (obj instanceof Integer integer) { - return new DyedColorModifier<>(integer); + return new DyedColorModifier<>(Color.fromDecimal(integer)); } else { Vector3f vector3f = MiscUtils.getAsVector3f(obj, "dyed-color"); - return new DyedColorModifier<>(0 << 24 /*不可省略*/ | MCUtils.fastFloor(vector3f.x) << 16 | MCUtils.fastFloor(vector3f.y) << 8 | MCUtils.fastFloor(vector3f.z)); + return new DyedColorModifier<>(Color.fromVector3f(vector3f)); } }, "dyed-color"); registerDataType((obj) -> { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 86b4c4729..f1692ece7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.data.Trim; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.item.setting.EquipmentData; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; @@ -69,9 +70,10 @@ public interface Item { int maxDamage(); - Item dyedColor(Integer data); + // todo 考虑部分版本的show in tooltip保留 + Item dyedColor(Color data); - Optional dyedColor(); + Optional dyedColor(); Item fireworkExplosion(FireworkExplosion explosion); @@ -208,4 +210,8 @@ public interface Item { } byte[] toByteArray(); + + boolean isDyeItem(); + + Optional dyeColor(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index 365582553..70d734922 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.item.data.Trim; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; @@ -135,9 +136,9 @@ public abstract class ItemFactory, I> { protected abstract void damage(W item, Integer damage); - protected abstract Optional dyedColor(W item); + protected abstract Optional dyedColor(W item); - protected abstract void dyedColor(W item, Integer color); + protected abstract void dyedColor(W item, Color color); protected abstract int maxDamage(W item); @@ -210,4 +211,8 @@ public abstract class ItemFactory, I> { protected abstract boolean isEmpty(W item); protected abstract UniqueKey recipeIngredientID(W item); + + protected abstract boolean isDyeItem(W item); + + protected abstract Optional dyeColor(W item); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 05b0bc297..841487680 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.util.Key; -public class ItemKeys { +public final class ItemKeys { public static final Key AIR = Key.of("minecraft:air"); public static final Key FLINT_AND_STEEL = Key.of("minecraft:flint_and_steel"); public static final Key STONE = Key.of("minecraft:stone"); @@ -44,6 +44,22 @@ public class ItemKeys { public static final Key GLOWSTONE = Key.of("minecraft:glowstone"); public static final Key SADDLE = Key.of("minecraft:saddle"); public static final Key HARNESS = Key.of("minecraft:harness"); + public static final Key WHITE_DYE = Key.of("minecraft:white_dye"); + public static final Key ORANGE_DYE = Key.of("minecraft:orange_dye"); + public static final Key MAGENTA_DYE = Key.of("minecraft:magenta_dye"); + public static final Key LIGHT_BLUE_DYE = Key.of("minecraft:light_blue_dye"); + public static final Key YELLOW_DYE = Key.of("minecraft:yellow_dye"); + public static final Key LIME_DYE = Key.of("minecraft:lime_dye"); + public static final Key PINK_DYE = Key.of("minecraft:pink_dye"); + public static final Key GRAY_DYE = Key.of("minecraft:gray_dye"); + public static final Key LIGHT_GRAY_DYE = Key.of("minecraft:light_gray_dye"); + public static final Key CYAN_DYE = Key.of("minecraft:cyan_dye"); + public static final Key PURPLE_DYE = Key.of("minecraft:purple_dye"); + public static final Key BLUE_DYE = Key.of("minecraft:blue_dye"); + public static final Key BROWN_DYE = Key.of("minecraft:brown_dye"); + public static final Key GREEN_DYE = Key.of("minecraft:green_dye"); + public static final Key RED_DYE = Key.of("minecraft:red_dye"); + public static final Key BLACK_DYE = Key.of("minecraft:black_dye"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index b55cc6de9..526f00969 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -30,7 +30,7 @@ public class ItemSettings { boolean renameable = true; boolean canPlaceRelatedVanillaBlock = false; ProjectileMeta projectileMeta; - boolean dyeable = true; + Tristate dyeable = Tristate.UNDEFINED; Helmet helmet = null; FoodData foodData = null; Key consumeReplacement = null; @@ -41,6 +41,8 @@ public class ItemSettings { boolean respectRepairableComponent = false; @Nullable ItemEquipment equipment; + @Nullable + Color dyeColor; private ItemSettings() {} @@ -99,6 +101,7 @@ public class ItemSettings { newSettings.canEnchant = settings.canEnchant; newSettings.compostProbability = settings.compostProbability; newSettings.respectRepairableComponent = settings.respectRepairableComponent; + newSettings.dyeColor = settings.dyeColor; return newSettings; } @@ -138,7 +141,7 @@ public class ItemSettings { return tags; } - public boolean dyeable() { + public Tristate dyeable() { return dyeable; } @@ -179,6 +182,11 @@ public class ItemSettings { return equipment; } + @Nullable + public Color dyeColor() { + return dyeColor; + } + public List invulnerable() { return invulnerable; } @@ -187,6 +195,11 @@ public class ItemSettings { return compostProbability; } + public ItemSettings dyeColor(Color color) { + this.dyeColor = color; + return this; + } + public ItemSettings repairItems(List items) { this.anvilRepairItems = items; return this; @@ -252,7 +265,7 @@ public class ItemSettings { return this; } - public ItemSettings dyeable(boolean bool) { + public ItemSettings dyeable(Tristate bool) { this.dyeable = bool; return this; } @@ -390,12 +403,19 @@ public class ItemSettings { })); registerFactory("dyeable", (value -> { boolean bool = ResourceConfigUtils.getAsBoolean(value, "dyeable"); - return settings -> settings.dyeable(bool); + return settings -> settings.dyeable(bool ? Tristate.TRUE : Tristate.FALSE); })); registerFactory("respect-repairable-component", (value -> { boolean bool = ResourceConfigUtils.getAsBoolean(value, "respect-repairable-component"); return settings -> settings.respectRepairableComponent(bool); })); + registerFactory("dye-color", (value -> { + if (value instanceof Integer i) { + return settings -> settings.dyeColor(Color.fromDecimal(i)); + } else { + return settings -> settings.dyeColor(Color.fromVector3f(MiscUtils.getAsVector3f(value, "dye-color"))); + } + })); registerFactory("food", (value -> { Map args = MiscUtils.castToMap(value, false); FoodData data = new FoodData( diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java index a93bbf284..f96536406 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java @@ -4,14 +4,15 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; public class DyedColorModifier implements ItemDataModifier { - private final int color; + private final Color color; - public DyedColorModifier(int color) { + public DyedColorModifier(Color color) { this.color = color; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java new file mode 100644 index 000000000..0e0201af5 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java @@ -0,0 +1,159 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; +import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.util.Color; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.Tristate; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class CustomDyeRecipe implements Recipe { + public static final Key ID = Key.of("armor_dye"); + private static final Key DYEABLE = Key.of("dyeable"); + + public CustomDyeRecipe() { + } + + @SuppressWarnings("unchecked") + @Override + public T assemble(RecipeInput input, ItemBuildContext context) { + List colors = new ArrayList<>(); + CraftingInput craftingInput = (CraftingInput) input; + Item itemToDye = null; + for (UniqueIdItem uniqueIdItem : craftingInput) { + if (uniqueIdItem.isEmpty()) { + continue; + } + if (isDyeable(uniqueIdItem)) { + itemToDye = uniqueIdItem.item().copyWithCount(1); + } else { + Color dyeColor = getDyeColor(uniqueIdItem); + if (dyeColor != null) { + colors.add(dyeColor); + } else { + return null; + } + } + } + if (itemToDye == null || itemToDye.isEmpty() || colors.isEmpty()) { + return null; + } + return applyDyes(itemToDye, colors).getItem(); + } + + private Item applyDyes(Item item, List colors) { + int totalRed = 0; + int totalGreen = 0; + int totalBlue = 0; + int totalMaxComponent = 0; + int colorCount = 0; + Optional existingColor = item.dyedColor(); + existingColor.ifPresent(colors::add); + for (Color color : colors) { + int dyeRed = color.r(); + int dyeGreen = color.g(); + int dyeBlue = color.b(); + totalMaxComponent += Math.max(dyeRed, Math.max(dyeGreen, dyeBlue)); + totalRed += dyeRed; + totalGreen += dyeGreen; + totalBlue += dyeBlue; + ++colorCount; + } + int avgRed = totalRed / colorCount; + int avgGreen = totalGreen / colorCount; + int avgBlue = totalBlue / colorCount; + float avgMaxComponent = (float) totalMaxComponent / (float)colorCount; + float currentMaxComponent = (float) Math.max(avgRed, Math.max(avgGreen, avgBlue)); + avgRed = (int) ((float) avgRed * avgMaxComponent / currentMaxComponent); + avgGreen = (int) ((float) avgGreen * avgMaxComponent / currentMaxComponent); + avgBlue = (int) ((float) avgBlue * avgMaxComponent / currentMaxComponent); + Color finalColor = new Color(0, avgRed, avgGreen, avgBlue); + return item.dyedColor(finalColor); + } + + @SuppressWarnings("unchecked") + @Override + public boolean matches(RecipeInput input) { + CraftingInput craftingInput = (CraftingInput) input; + if (craftingInput.ingredientCount() < 2) { + return false; + } + boolean hasItemToDye = false; + boolean hasDye = false; + for(int i = 0; i < craftingInput.size(); ++i) { + UniqueIdItem item = craftingInput.getItem(i); + if (!item.isEmpty()) { + if (isDyeable(item)) { + if (hasItemToDye) { + return false; + } + hasItemToDye = true; + } else { + if (!isDye(item)) { + return false; + } + hasDye = true; + } + } + } + return hasDye && hasItemToDye; + } + + private boolean isDyeable(final UniqueIdItem item) { + Optional> optionalCustomItem = item.item().getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + if (customItem.settings().dyeable() == Tristate.FALSE) { + return false; + } + if (customItem.settings().dyeable() == Tristate.TRUE) { + return true; + } + } + return item.item().is(DYEABLE); + } + + private boolean isDye(final UniqueIdItem item) { + Item dyeItem = item.item(); + Optional> optionalCustomItem = item.item().getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + return customItem.settings().dyeColor() != null || dyeItem.isDyeItem(); + } + return dyeItem.isDyeItem(); + } + + @Nullable + private Color getDyeColor(final UniqueIdItem item) { + Item dyeItem = item.item(); + Optional> optionalCustomItem = item.item().getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + return Optional.ofNullable(customItem.settings().dyeColor()).orElseGet(() -> dyeItem.dyeColor().orElse(null)); + } + return dyeItem.dyeColor().orElse(null); + } + + @Override + public List> ingredientsInUse() { + return List.of(); + } + + @Override + public @NotNull Key type() { + return RecipeTypes.SPECIAL; + } + + @Override + public Key id() { + return ID; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java index 603c76840..d4b7ee61a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java @@ -21,6 +21,7 @@ public class RecipeTypes { public static final Key SMITHING_TRANSFORM = Key.of("minecraft:smithing_transform"); public static final Key SMITHING_TRIM = Key.of("minecraft:smithing_trim"); public static final Key BREWING = Key.of("minecraft:brewing"); + public static final Key SPECIAL = Key.of("minecraft:special"); static { register(SHAPED, CustomShapedRecipe.FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java index e07cac354..c08a45f86 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java @@ -2,12 +2,14 @@ package net.momirealms.craftengine.core.item.recipe.input; import net.momirealms.craftengine.core.item.recipe.RecipeFinder; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; -public final class CraftingInput implements RecipeInput { +public final class CraftingInput implements RecipeInput, Iterable> { private final int width; private final int height; private final List> items; @@ -99,4 +101,9 @@ public final class CraftingInput implements RecipeInput { public UniqueIdItem getItem(int index) { return this.items.get(index); } + + @Override + public @NotNull Iterator> iterator() { + return this.items.iterator(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java index bc65826b4..2ab73db03 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java @@ -38,7 +38,7 @@ public class ParticleFunction extends AbstractConditionalFu })), ParticleTypes.BLOCK, ParticleTypes.FALLING_DUST, ParticleTypes.DUST_PILLAR, ParticleTypes.BLOCK_CRUMBLE, ParticleTypes.BLOCK_MARKER); registerParticleData(map -> new ColorData( - Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))), + Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))), ParticleTypes.ENTITY_EFFECT, ParticleTypes.TINTED_LEAVES); registerParticleData(map -> new JavaTypeData( ResourceConfigUtils.getAsFloat(map.get("charge"), "charge")), @@ -47,12 +47,12 @@ public class ParticleFunction extends AbstractConditionalFu ResourceConfigUtils.getAsInt(map.get("shriek"), "shriek")), ParticleTypes.SHRIEK); registerParticleData(map -> new DustData( - Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), + Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")), ParticleTypes.DUST); registerParticleData(map -> new DustTransitionData( - Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")), - Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")), + Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")), + Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")), ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")), ParticleTypes.DUST_COLOR_TRANSITION); registerParticleData(map -> new ItemStackData( @@ -75,7 +75,7 @@ public class ParticleFunction extends AbstractConditionalFu NumberProviders.fromObject(map.getOrDefault("target-x", 0)), NumberProviders.fromObject(map.getOrDefault("target-y", 0)), NumberProviders.fromObject(map.getOrDefault("target-z", 0)), - Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), + Color.fromStrings(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), NumberProviders.fromObject(map.getOrDefault("duration", 10))), ParticleTypes.TRAIL); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Color.java b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java index 0e47529c1..6884afedd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Color.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java @@ -1,52 +1,95 @@ package net.momirealms.craftengine.core.util; +import org.joml.Vector3f; + import java.util.Arrays; public class Color { + private static final int BIT_MASK = 0xff; private static final byte DEFAULT_ALPHA = (byte) 255; - private final byte r; - private final byte g; - private final byte b; - private final byte a; + private final int color; - public Color(byte r, byte g, byte b, byte a) { - this.b = b; - this.g = g; - this.r = r; - this.a = a; + public Color(int color) { + this.color = color; } - public Color(byte r, byte g, byte b) { - this(r, g, b, DEFAULT_ALPHA); + public Color(int r, int g, int b) { + this(DEFAULT_ALPHA, r, g, b); } - public int toDecimal() { - return DEFAULT_ALPHA << 24 | (r << 16) | (g << 8) | b; + public Color(int a, int r, int g, int b) { + this(toDecimal(a, r, g, b)); } - public static Color fromString(String[] strings) { + public int color() { + return color; + } + + public static int toDecimal(int a, int r, int g, int b) { + return a << 24 | r << 16 | g << 8 | b; + } + + public static int toDecimal(int r, int g, int b) { + return DEFAULT_ALPHA << 24 | r << 16 | g << 8 | b; + } + + public static Color fromDecimal(int decimal) { + return new Color(decimal); + } + + public static Color fromVector3f(Vector3f vec) { + return new Color(0 << 24 /*不可省略*/ | MCUtils.fastFloor(vec.x) << 16 | MCUtils.fastFloor(vec.y) << 8 | MCUtils.fastFloor(vec.z)); + } + + public static int opaque(int color) { + return color | -16777216; + } + + public static int transparent(int color) { + return color & 16777215; + } + + public static int alpha(int color) { + return color >>> 24; + } + + public static int red(int color) { + return color >> 16 & BIT_MASK; + } + + public static int green(int color) { + return color >> 8 & BIT_MASK; + } + + public static int blue(int color) { + return color & BIT_MASK; + } + + public static Color fromStrings(String[] strings) { if (strings.length == 3) { - return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2])); + // rgb + return fromDecimal(toDecimal(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), Integer.parseInt(strings[2]))); } else if (strings.length == 4) { - return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2]), Byte.parseByte(strings[3])); + // argb + return fromDecimal(toDecimal(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), Integer.parseInt(strings[2]), Integer.parseInt(strings[3]))); } else { throw new IllegalArgumentException("Invalid color format: " + Arrays.toString(strings)); } } - public byte a() { - return a; + public int a() { + return alpha(color); } - public byte b() { - return b; + public int b() { + return blue(color); } - public byte g() { - return g; + public int g() { + return green(color); } - public byte r() { - return r; + public int r() { + return red(color); } } diff --git a/gradle.properties b/gradle.properties index 9026ef29a..829302ea9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.7 +project_version=0.0.60.8 config_version=43 lang_version=22 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.18 -nms_helper_version=1.0.39 +nms_helper_version=1.0.43 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 663236a15300ca34df7e3c11f245033ecc3cd2bf Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 30 Jul 2025 15:56:24 +0800 Subject: [PATCH 63/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=94=AF=E6=8C=81=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/config.yml | 6 +++++- .../momirealms/craftengine/core/plugin/config/Config.java | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index ca645f6ba..f7ea43ab2 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -57,8 +57,12 @@ resource-pack: enable: true # Define the name of the overlay folders overlay-format: "ce_overlay_{version}" + # Allowed values: + # - 1.20.1, 1.21, 1.21.8, etc. + # - LATEST: the latest client version + # - SERVER: the current server version supported-version: - min: "1.20" + min: SERVER max: LATEST # Remove 1.21.5+ tinted_leaves particles remove-tinted-leaves-particle: true diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 0f3c2d5d6..2e75b7f84 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -20,10 +20,7 @@ import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MinecraftVersion; -import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.InjectionTarget; import net.momirealms.craftengine.core.world.chunk.storage.CompressionMethod; @@ -409,6 +406,9 @@ public class Config { if (version.equalsIgnoreCase("LATEST")) { return new MinecraftVersion(PluginProperties.getValue("latest-version")); } + if (version.equalsIgnoreCase("SERVER")) { + return VersionHelper.MINECRAFT_VERSION; + } return MinecraftVersion.parse(version); } From 0eb14732a5a8c1ce267c623c026b1318fb37f4b7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 30 Jul 2025 16:19:29 +0800 Subject: [PATCH 64/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BD=8E=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=90=AF=E5=8A=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/core/pack/revision/Revision.java | 2 +- .../momirealms/craftengine/core/plugin/config/Config.java | 5 ++++- .../momirealms/craftengine/core/util/ReflectionUtils.java | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revision.java b/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revision.java index 849123084..c6547ac9d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revision.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revision.java @@ -55,7 +55,7 @@ public interface Revision { @Override public boolean matches(MinecraftVersion min, MinecraftVersion max) { - return this.minVersion.isAtOrBelow(max); + return this.minVersion.isAtOrBelow(max) && min.isBelow(this.minVersion); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 2e75b7f84..8439a43d6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -251,8 +251,11 @@ public class Config { resource_pack$override_uniform_font = config.getBoolean("resource-pack.override-uniform-font", false); resource_pack$generate_mod_assets = config.getBoolean("resource-pack.generate-mod-assets", false); resource_pack$remove_tinted_leaves_particle = config.getBoolean("resource-pack.remove-tinted-leaves-particle", true); - resource_pack$supported_version$min = getVersion(config.get("resource-pack.supported-version.min", "1.20").toString()); + resource_pack$supported_version$min = getVersion(config.get("resource-pack.supported-version.min", "SERVER").toString()); resource_pack$supported_version$max = getVersion(config.get("resource-pack.supported-version.max", "LATEST").toString()); + if (resource_pack$supported_version$min.isAbove(resource_pack$supported_version$max)) { + resource_pack$supported_version$min = resource_pack$supported_version$max; + } resource_pack$merge_external_folders = config.getStringList("resource-pack.merge-external-folders"); resource_pack$merge_external_zips = config.getStringList("resource-pack.merge-external-zip-files"); resource_pack$exclude_file_extensions = new HashSet<>(config.getStringList("resource-pack.exclude-file-extensions")); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java index 4ac327b00..fa7b61ce5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java @@ -74,7 +74,7 @@ public class ReflectionUtils { } } - @NotNull + @Nullable public static Field getDeclaredField(@NotNull Class clazz, @NotNull String... possibleNames) { List possibleNameList = Arrays.asList(possibleNames); for (Field field : clazz.getDeclaredFields()) { @@ -82,7 +82,7 @@ public class ReflectionUtils { return field; } } - throw new RuntimeException("Class " + clazz.getName() + " does not contain a field with possible names " + Arrays.toString(possibleNames)); + return null; } @Nullable From a19561984c09646a1d1e13dc7afc24e01cd56f92 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 30 Jul 2025 16:54:29 +0800 Subject: [PATCH 65/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E6=94=B6=E9=9B=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/AbstractItemManager.java | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 79ee3ad6a..2f5baff69 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -21,12 +21,16 @@ import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenera import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; +import net.momirealms.craftengine.core.pack.obfuscation.ResourcePackGenerationException; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.text.TextProvider; import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.*; @@ -334,6 +338,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl throw new LocalizedResourceConfigException("warning.config.item.duplicate"); } + ExceptionCollector collector = new ExceptionCollector<>(); + UniqueKey uniqueId = UniqueKey.create(id); // 判断是不是原版物品 boolean isVanillaItem = isVanillaItem(id); @@ -381,21 +387,43 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } // 应用物品数据 - applyDataFunctions(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); - applyDataFunctions(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); - + try { + applyDataFunctions(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + } + try { + applyDataFunctions(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + } // 如果不是原版物品,那么加入ce的标识符 if (!isVanillaItem) itemBuilder.dataModifier(new IdModifier<>(id)); + Map>> eventTriggerListMap; + try { + eventTriggerListMap = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + eventTriggerListMap = Map.of(); + } + + ItemSettings settings; + try { + settings = Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) + .map(map -> ItemSettings.fromMap(MiscUtils.castToMap(map, true))) + .map(it -> isVanillaItem ? it.canPlaceRelatedVanillaBlock(true) : it) + .orElse(ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem)); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + settings = ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem); + } // 构建自定义物品 CustomItem customItem = itemBuilder .behaviors(ItemBehaviors.fromObj(pack, path, id, ResourceConfigUtils.get(section, "behavior", "behaviors"))) - .settings(Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) - .map(map -> ItemSettings.fromMap(MiscUtils.castToMap(map, true))) - .map(it -> isVanillaItem ? it.canPlaceRelatedVanillaBlock(true) : it) - .orElse(ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem))) - .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) + .settings(settings) + .events(eventTriggerListMap) .build(); // 添加到缓存 addCustomItem(customItem); @@ -405,6 +433,9 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl AbstractItemManager.this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); } + // 抛出异常 + collector.throwIfPresent(); + // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model Map modelSection = MiscUtils.castToMap(section.get("model"), true); Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); From cd43273d4cd32e2e3a5036c2e54e6c3a2976bee0 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 30 Jul 2025 20:41:32 +0800 Subject: [PATCH 66/83] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=89=A9=E5=93=81?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/LegacyNetworkItemHandler.java | 4 +- .../bukkit/item/ModernNetworkItemHandler.java | 4 +- .../factory/ComponentItemFactory1_20_5.java | 37 ++- .../factory/ComponentItemFactory1_21_5.java | 30 ++ .../item/factory/UniversalItemFactory.java | 20 ++ .../src/main/resources/translations/en.yml | 4 + .../src/main/resources/translations/zh_cn.yml | 1 + .../core/attribute/AttributeModifier.java | 3 +- .../craftengine/core/item/AbstractItem.java | 7 + .../core/item/AbstractItemManager.java | 272 ++++-------------- .../craftengine/core/item/Item.java | 3 + .../core/item/ItemDataModifierFactory.java | 8 + .../craftengine/core/item/ItemFactory.java | 3 + .../craftengine/core/item/ItemManager.java | 6 - ...ntModifier.java => ArgumentsModifier.java} | 30 +- .../modifier/AttributeModifiersModifier.java | 142 ++++----- ...tModifier.java => ComponentsModifier.java} | 26 +- .../modifier/CustomModelDataModifier.java | 55 ++-- .../item/modifier/CustomNameModifier.java | 54 ++-- .../core/item/modifier/DyedColorModifier.java | 59 ++-- .../item/modifier/EnchantmentModifier.java | 70 ----- .../item/modifier/EnchantmentsModifier.java | 68 +++++ .../modifier/EquippableAssetIdModifier.java | 24 +- .../item/modifier/EquippableModifier.java | 35 ++- .../core/item/modifier/ExternalModifier.java | 33 ++- .../core/item/modifier/FoodModifier.java | 45 ++- .../item/modifier/HideTooltipModifier.java | 19 +- .../core/item/modifier/IdModifier.java | 8 +- .../core/item/modifier/ItemDataModifier.java | 3 +- .../core/item/modifier/ItemDataModifiers.java | 88 ++++++ .../core/item/modifier/ItemModelModifier.java | 36 ++- .../core/item/modifier/ItemNameModifier.java | 54 ++-- .../item/modifier/JukeboxSongModifier.java | 20 +- .../modifier/RemoveComponentModifier.java | 19 +- .../SimpleNetworkItemDataModifier.java | 61 ++++ .../core/item/modifier/TagsModifier.java | 24 +- .../item/modifier/TooltipStyleModifier.java | 33 ++- .../core/item/modifier/TrimModifier.java | 66 +++-- .../item/modifier/UnbreakableModifier.java | 55 ++-- .../modifier/lore/DynamicLoreModifier.java | 54 ++-- .../core/item/modifier/lore/LoreModifier.java | 68 +++-- .../core/item/recipe/CustomRecipeResult.java | 6 +- .../core/pack/AbstractPackManager.java | 19 +- .../context/number/FixedNumberProvider.java | 4 + .../core/registry/BuiltInRegistries.java | 2 + .../craftengine/core/registry/Registries.java | 2 + .../core/util/ExceptionCollector.java | 5 + .../core/util/ResourceConfigUtils.java | 8 + .../craftengine/core/util/VersionHelper.java | 3 + gradle.properties | 4 +- 50 files changed, 1031 insertions(+), 673 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/ItemDataModifierFactory.java rename core/src/main/java/net/momirealms/craftengine/core/item/modifier/{ArgumentModifier.java => ArgumentsModifier.java} (59%) rename core/src/main/java/net/momirealms/craftengine/core/item/modifier/{ComponentModifier.java => ComponentsModifier.java} (80%) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/SimpleNetworkItemDataModifier.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index 6c4d94cf2..aa98ccc73 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.item.modifier.ArgumentModifier; +import net.momirealms.craftengine.core.item.modifier.ArgumentsModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; @@ -74,7 +74,7 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler { @@ -129,7 +128,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory modifierList) { + CompoundTag compoundTag = (CompoundTag) item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS).orElseGet(CompoundTag::new); + ListTag modifiers = new ListTag(); + compoundTag.put("modifiers", modifiers); + for (AttributeModifier modifier : modifierList) { + CompoundTag modifierTag = new CompoundTag(); + modifierTag.putString("type", modifier.type()); + modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); + if (VersionHelper.isOrAbove1_21()) { + modifierTag.putString("id", modifier.id().toString()); + } else { + modifierTag.putIntArray("uuid", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8)))); + modifierTag.putString("name", modifier.id().toString()); + } + modifierTag.putDouble("amount", modifier.amount()); + modifierTag.putString("operation", modifier.operation().id()); + modifiers.add(modifierTag); + } + item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, compoundTag); + } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java index af0981b60..fff53ba54 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java @@ -5,15 +5,20 @@ import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; +import net.momirealms.craftengine.core.attribute.AttributeModifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.GsonHelper; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.ListTag; import net.momirealms.sparrow.nbt.Tag; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Optional; public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { @@ -123,4 +128,29 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { protected void jukeboxSong(ComponentItemWrapper item, JukeboxPlayable data) { item.setJavaComponent(ComponentTypes.JUKEBOX_PLAYABLE, data.song()); } + + @Override + protected void attributeModifiers(ComponentItemWrapper item, List modifierList) { + ListTag modifiers = new ListTag(); + for (AttributeModifier modifier : modifierList) { + CompoundTag modifierTag = new CompoundTag(); + modifierTag.putString("type", modifier.type()); + modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); + modifierTag.putString("id", modifier.id().toString()); + modifierTag.putDouble("amount", modifier.amount()); + modifierTag.putString("operation", modifier.operation().id()); + AttributeModifier.Display display = modifier.display(); + if (VersionHelper.isOrAbove1_21_6() && display != null) { + CompoundTag displayTag = new CompoundTag(); + AttributeModifier.Display.Type displayType = display.type(); + displayTag.putString("type", displayType.name().toLowerCase(Locale.ENGLISH)); + if (displayType == AttributeModifier.Display.Type.OVERRIDE) { + displayTag.put("value", AdventureHelper.componentToTag(display.value())); + } + modifierTag.put("display", displayTag); + } + modifiers.add(modifierTag); + } + item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, modifiers); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index c8437d089..6d4c2456a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.attribute.AttributeModifier; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.data.Trim; @@ -13,6 +14,9 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.SkullUtils; +import net.momirealms.craftengine.core.util.UUIDUtils; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.ListTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.NamespacedKey; import org.bukkit.Registry; @@ -344,4 +348,20 @@ public class UniversalItemFactory extends BukkitItemFactory { FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, FastNMS.INSTANCE.method$CompoundTag$copy(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject()))); return new LegacyItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(newItemStack)); } + + @Override + protected void attributeModifiers(LegacyItemWrapper item, List modifiers) { + ListTag listTag = new ListTag(); + for (AttributeModifier modifier : modifiers) { + CompoundTag modifierTag = new CompoundTag(); + modifierTag.putString("AttributeName", modifier.type()); + modifierTag.putString("Name", modifier.id().toString()); + modifierTag.putString("Slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); + modifierTag.putInt("Operation", modifier.operation().ordinal()); + modifierTag.putDouble("Amount", modifier.amount()); + modifierTag.putIntArray("UUID", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8)))); + listTag.add(modifierTag); + } + item.setTag(listTag, "AttributeModifiers"); + } } \ No newline at end of file diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 3f4624266..8f0f5a79a 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -72,6 +72,7 @@ warning.config.type.float: "Issue found in file - Failed to load warning.config.type.double: "Issue found in file - Failed to load '': Cannot cast '' to double type for option ''." warning.config.type.quaternionf: "Issue found in file - Failed to load '': Cannot cast '' to Quaternionf type for option ''." warning.config.type.vector3f: "Issue found in file - Failed to load '': Cannot cast '' to Vector3f type for option ''." +warning.config.type.map: "Issue found in file - Failed to load '': Cannot cast '' to Map type for option ''." warning.config.type.snbt.invalid_syntax: "Issue found in file - Failed to load '': Invalid snbt syntax ''." warning.config.number.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for number argument." warning.config.number.invalid_type: "Issue found in file - The config '' is using an invalid number argument type ''." @@ -173,6 +174,9 @@ warning.config.item.data.attribute_modifiers.missing_amount: "Issue foun warning.config.item.data.attribute_modifiers.missing_operation: "Issue found in file - The item '' is missing the required 'operation' argument for 'attribute-modifiers' data." warning.config.item.data.attribute_modifiers.display.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for 'attribute-modifiers' display data." warning.config.item.data.attribute_modifiers.display.missing_value: "Issue found in file - The item '' is missing the required 'value' argument for 'attribute-modifiers' display data." +warning.config.item.data.external.missing_source: "Issue found in file - The item '' is missing the required 'source' argument for 'external' data." +warning.config.item.data.external.missing_id: "Issue found in file - The item '' is missing the required 'id' argument for 'external' data." +warning.config.item.data.external.invalid_source: "Issue found in file - The item '' is using an invalid item source '' for 'external' data." warning.config.item.missing_material: "Issue found in file - The item '' is missing the required 'material' argument." warning.config.item.invalid_material: "Issue found in file - The item '' is using an invalid material type ''." warning.config.item.invalid_custom_model_data: "Issue found in file - The item '' is using a negative custom model data '' which is invalid." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 2666687a4..77a18b454 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -72,6 +72,7 @@ warning.config.type.boolean: "在文件 发现问题 - 无法加 warning.config.type.double: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为双精度类型 (选项 '')" warning.config.type.quaternionf: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为四元数类型 (选项 '')" warning.config.type.vector3f: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为三维向量类型 (选项 '')" +warning.config.type.map: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为映射类型 (选项 '')" warning.config.type.snbt.invalid_syntax: "在文件 发现问题 - 无法加载 '': 无效的 SNBT 语法 ''." warning.config.number.missing_type: "在文件 发现问题 - 配置项 '' 缺少数字类型所需的 'type' 参数" warning.config.number.invalid_type: "在文件 发现问题 - 配置项 '' 使用了无效的数字类型 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/attribute/AttributeModifier.java b/core/src/main/java/net/momirealms/craftengine/core/attribute/AttributeModifier.java index 0d5ff2dfb..1353e5769 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/attribute/AttributeModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/attribute/AttributeModifier.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.attribute; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -72,7 +73,7 @@ public class AttributeModifier { } } - public record Display(AttributeModifier.Display.Type type, String value) { + public record Display(AttributeModifier.Display.Type type, Component value) { public enum Type { DEFAULT, HIDDEN, OVERRIDE diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 33170ded2..872aa411d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.attribute.AttributeModifier; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; @@ -253,6 +254,12 @@ public class AbstractItem, I> implements Item { return this.factory.loreComponent(this.item); } + @Override + public Item attributeModifiers(List modifiers) { + this.factory.attributeModifiers(this.item, modifiers); + return this; + } + @Override public Item unbreakable(boolean unbreakable) { this.factory.unbreakable(this.item, unbreakable); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 2f5baff69..f8d415982 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -2,16 +2,10 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; -import net.momirealms.craftengine.core.attribute.AttributeModifier; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; -import net.momirealms.craftengine.core.item.data.Enchantment; -import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.equipment.*; import net.momirealms.craftengine.core.item.modifier.*; -import net.momirealms.craftengine.core.item.modifier.lore.DynamicLoreModifier; -import net.momirealms.craftengine.core.item.modifier.lore.LoreModifier; -import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; @@ -21,27 +15,22 @@ import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenera import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; -import net.momirealms.craftengine.core.pack.obfuscation.ResourcePackGenerationException; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; -import net.momirealms.craftengine.core.plugin.context.text.TextProvider; -import net.momirealms.craftengine.core.plugin.context.text.TextProviders; -import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.type.Either; -import org.joml.Vector3f; import java.nio.file.Path; import java.util.*; import java.util.function.Consumer; -import java.util.function.Function; import java.util.stream.Stream; public abstract class AbstractItemManager extends AbstractModelGenerator implements ItemManager { @@ -52,7 +41,6 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl private final ItemParser itemParser; private final EquipmentParser equipmentParser; protected final Map> externalItemSources = new HashMap<>(); - protected final Map>> dataFunctions = new HashMap<>(); protected final Map> customItems = new HashMap<>(); protected final Map> customItemTags = new HashMap<>(); protected final Map> cmdConflictChecker = new HashMap<>(); @@ -69,14 +57,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl super(plugin); this.itemParser = new ItemParser(); this.equipmentParser = new EquipmentParser(); - this.registerFunctions(); - } - - @Override - public void registerDataType(Function> factory, String... alias) { - for (String a : alias) { - this.dataFunctions.put(a, factory); - } + ItemDataModifiers.init(); } protected static void registerVanillaItemExtraBehavior(ItemBehavior behavior, Key... items) { @@ -85,23 +66,23 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } - protected void applyDataFunctions(Map dataSection, Consumer> consumer) { + @SuppressWarnings("unchecked") + protected void applyDataModifiers(Map dataSection, Consumer> callback) { + ExceptionCollector errorCollector = new ExceptionCollector<>(); if (dataSection != null) { for (Map.Entry dataEntry : dataSection.entrySet()) { - Optional.ofNullable(this.dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { + Object value = dataEntry.getValue(); + if (value == null) continue; + Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(dataEntry.getKey(), Key.DEFAULT_NAMESPACE))).ifPresent(factory -> { try { - consumer.accept(function.apply(dataEntry.getValue())); - } catch (IllegalArgumentException e) { - this.plugin.logger().warn("Invalid data format", e); + callback.accept((ItemDataModifier) factory.create(value)); + } catch (LocalizedResourceConfigException e) { + errorCollector.add(e); } }); } } - } - - @Override - public Function> getDataType(String key) { - return this.dataFunctions.get(key); + errorCollector.throwIfPresent(); } @Override @@ -338,8 +319,6 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl throw new LocalizedResourceConfigException("warning.config.item.duplicate"); } - ExceptionCollector collector = new ExceptionCollector<>(); - UniqueKey uniqueId = UniqueKey.create(id); // 判断是不是原版物品 boolean isVanillaItem = isVanillaItem(id); @@ -386,21 +365,26 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl else itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); } + // 对于不重要的配置,可以仅警告,不返回 + ExceptionCollector collector = new ExceptionCollector<>(); + // 应用物品数据 try { - applyDataFunctions(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); + applyDataModifiers(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); } catch (LocalizedResourceConfigException e) { collector.add(e); } - try { - applyDataFunctions(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); - } catch (LocalizedResourceConfigException e) { - collector.add(e); - } + try { + applyDataModifiers(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + } + // 如果不是原版物品,那么加入ce的标识符 if (!isVanillaItem) itemBuilder.dataModifier(new IdModifier<>(id)); + // 事件 Map>> eventTriggerListMap; try { eventTriggerListMap = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); @@ -409,6 +393,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl eventTriggerListMap = Map.of(); } + // 设置 ItemSettings settings; try { settings = Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) @@ -419,12 +404,23 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl collector.add(e); settings = ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem); } + + // 行为 + List behaviors; + try { + behaviors = ItemBehaviors.fromObj(pack, path, id, ResourceConfigUtils.get(section, "behavior", "behaviors")); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + behaviors = Collections.emptyList(); + } + // 构建自定义物品 CustomItem customItem = itemBuilder - .behaviors(ItemBehaviors.fromObj(pack, path, id, ResourceConfigUtils.get(section, "behavior", "behaviors"))) + .behaviors(behaviors) .settings(settings) .events(eventTriggerListMap) .build(); + // 添加到缓存 addCustomItem(customItem); @@ -433,13 +429,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl AbstractItemManager.this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); } - // 抛出异常 - collector.throwIfPresent(); - // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model Map modelSection = MiscUtils.castToMap(section.get("model"), true); Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); if (modelSection == null && legacyModelSection == null) { + collector.throwIfPresent(); return; } @@ -448,39 +442,47 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl if (!isVanillaItem) { // 既没有模型值也没有item-model if (customModelData == 0 && itemModelKey == null) { - throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model_id")); } } - // 1.21.4+必须要配置model区域,如果不需要高版本兼容,则可以只写legacy-model - if (needsModelSection && modelSection == null) { - throw new LocalizedResourceConfigException("warning.config.item.missing_model"); - } - // 新版格式 ItemModel modernModel = null; // 旧版格式 TreeSet legacyOverridesModels = null; // 如果需要支持新版item model 或者用户需要旧版本兼容,但是没配置legacy-model if (needsModelSection) { - modernModel = ItemModels.fromMap(modelSection); - for (ModelGeneration generation : modernModel.modelsToGenerate()) { - prepareModelGeneration(generation); + // 1.21.4+必须要配置model区域,如果不需要高版本兼容,则可以只写legacy-model + if (modelSection == null) { + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model")); + return; + } + try { + modernModel = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : modernModel.modelsToGenerate()) { + prepareModelGeneration(generation); + } + } catch (LocalizedResourceConfigException e) { + collector.addAndThrow(e); } } // 如果需要旧版本兼容 if (needsLegacyCompatibility()) { if (legacyModelSection != null) { - LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection, customModelData); - for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { - prepareModelGeneration(generation); + try { + LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection, customModelData); + for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { + prepareModelGeneration(generation); + } + legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); + } catch (LocalizedResourceConfigException e) { + collector.addAndThrow(e); } - legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); } else { legacyOverridesModels = new TreeSet<>(); processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, clientBoundMaterial, customModelData); if (legacyOverridesModels.isEmpty()) { - TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString()); + collector.add(new LocalizedResourceConfigException("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString())); } } } @@ -496,7 +498,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 检查cmd冲突 Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(finalBaseModel, k -> new HashMap<>()); if (conflict.containsKey(customModelData)) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString())); } conflict.put(customModelData, id); // 添加新版item model @@ -514,7 +516,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl lom.addAll(legacyOverridesModels); } } else if (isVanillaItemModel) { - throw new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModelKey.asString()); + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModelKey.asString())); } // 使用了item-model组件,且不是原版物品的 @@ -541,157 +543,9 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl )); } } - } - } - private void registerFunctions() { - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - String plugin = data.get("plugin").toString(); - String id = data.get("id").toString(); - ExternalItemSource provider = AbstractItemManager.this.getExternalItemSource(plugin.toLowerCase(Locale.ENGLISH)); - return new ExternalModifier<>(id, Objects.requireNonNull(provider, "Item provider " + plugin + " not found")); - }, "external"); - if (VersionHelper.isOrAbove1_20_5()) { - registerDataType((obj) -> { - String name = obj.toString(); - return new CustomNameModifier<>(name); - }, "custom-name"); - registerDataType((obj) -> { - String name = obj.toString(); - return new ItemNameModifier<>(name); - }, "item-name", "display-name"); - } else { - registerDataType((obj) -> { - String name = obj.toString(); - return new CustomNameModifier<>(name); - }, "custom-name", "item-name", "display-name"); - } - registerDataType(LoreModifier::createLoreModifier, "lore", "display-lore", "description"); - registerDataType((obj) -> { - Map> dynamicLore = new LinkedHashMap<>(); - if (obj instanceof Map map) { - for (Map.Entry entry : map.entrySet()) { - dynamicLore.put(entry.getKey().toString(), LoreModifier.createLoreModifier(entry.getValue())); - } - } - return new DynamicLoreModifier<>(dynamicLore); - }, "dynamic-lore"); - registerDataType((obj) -> { - if (obj instanceof Integer integer) { - return new DyedColorModifier<>(Color.fromDecimal(integer)); - } else { - Vector3f vector3f = MiscUtils.getAsVector3f(obj, "dyed-color"); - return new DyedColorModifier<>(Color.fromVector3f(vector3f)); - } - }, "dyed-color"); - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - return new TagsModifier<>(data); - }, "tags", "tag", "nbt"); - registerDataType((object -> { - MutableInt mutableInt = new MutableInt(0); - List attributeModifiers = ResourceConfigUtils.parseConfigAsList(object, (map) -> { - String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.data.attribute_modifiers.missing_type"); - Key nativeType = AttributeModifiersModifier.getNativeAttributeName(Key.of(type)); - AttributeModifier.Slot slot = AttributeModifier.Slot.valueOf(map.getOrDefault("slot", "any").toString().toUpperCase(Locale.ENGLISH)); - Key id = Optional.ofNullable(map.get("id")).map(String::valueOf).map(Key::of).orElseGet(() -> { - mutableInt.add(1); - return Key.of("craftengine", "modifier_" + mutableInt.intValue()); - }); - double amount = ResourceConfigUtils.getAsDouble( - ResourceConfigUtils.requireNonNullOrThrow(map.get("amount"), "warning.config.item.data.attribute_modifiers.missing_amount"), "amount" - ); - AttributeModifier.Operation operation = AttributeModifier.Operation.valueOf( - ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("operation"), "warning.config.item.data.attribute_modifiers.missing_operation").toUpperCase(Locale.ENGLISH) - ); - AttributeModifier.Display display = null; - if (VersionHelper.isOrAbove1_21_6() && map.containsKey("display")) { - Map displayMap = MiscUtils.castToMap(map.get("display"), false); - AttributeModifier.Display.Type displayType = AttributeModifier.Display.Type.valueOf(ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("type"), "warning.config.item.data.attribute_modifiers.display.missing_type").toUpperCase(Locale.ENGLISH)); - if (displayType == AttributeModifier.Display.Type.OVERRIDE) { - String miniMessageValue = ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("value"), "warning.config.item.data.attribute_modifiers.display.missing_value"); - display = new AttributeModifier.Display(displayType, miniMessageValue); - } else { - display = new AttributeModifier.Display(displayType, null); - } - } - return new AttributeModifier(nativeType.value(), slot, id, - amount, operation, display); - }); - return new AttributeModifiersModifier<>(attributeModifiers); - }), "attributes", "attribute-modifiers", "attribute-modifier"); - registerDataType((obj) -> { - boolean value = TypeUtils.checkType(obj, Boolean.class); - return new UnbreakableModifier<>(value); - }, "unbreakable"); - registerDataType((obj) -> { - int customModelData = ResourceConfigUtils.getAsInt(obj, "custom-model-data"); - return new CustomModelDataModifier<>(customModelData); - }, "custom-model-data"); - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - List enchantments = new ArrayList<>(); - for (Map.Entry e : data.entrySet()) { - if (e.getValue() instanceof Number number) { - enchantments.add(new Enchantment(Key.of(e.getKey()), number.intValue())); - } - } - return new EnchantmentModifier<>(enchantments); - }, "enchantment", "enchantments", "enchant"); - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - String material = data.get("material").toString().toLowerCase(Locale.ENGLISH); - String pattern = data.get("pattern").toString().toLowerCase(Locale.ENGLISH); - return new TrimModifier<>(Key.of(material), Key.of(pattern)); - }, "trim"); - registerDataType((obj) -> { - List components = MiscUtils.getAsStringList(obj).stream().map(Key::of).toList(); - return new HideTooltipModifier<>(components); - }, "hide-tooltip", "hide-flags"); - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - Map arguments = new HashMap<>(); - for (Map.Entry entry : data.entrySet()) { - arguments.put(entry.getKey(), TextProviders.fromString(entry.getValue().toString())); - } - return new ArgumentModifier<>(arguments); - }, "args", "argument", "arguments"); - if (VersionHelper.isOrAbove1_20_5()) { - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - return new ComponentModifier<>(data); - }, "components", "component"); - registerDataType((obj) -> { - List data = MiscUtils.getAsStringList(obj); - return new RemoveComponentModifier<>(data); - }, "remove-components", "remove-component"); - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - int nutrition = ResourceConfigUtils.getAsInt(data.get("nutrition"), "nutrition"); - float saturation = ResourceConfigUtils.getAsFloat(data.get("saturation"), "saturation"); - return new FoodModifier<>(nutrition, saturation, ResourceConfigUtils.getAsBoolean(data.getOrDefault("can-always-eat", false), "can-always-eat")); - }, "food"); - } - if (VersionHelper.isOrAbove1_21()) { - registerDataType((obj) -> { - String song = obj.toString(); - return new JukeboxSongModifier<>(new JukeboxPlayable(song, true)); - }, "jukebox-playable"); - } - if (VersionHelper.isOrAbove1_21_2()) { - registerDataType((obj) -> { - String id = obj.toString(); - return new TooltipStyleModifier<>(Key.of(id)); - }, "tooltip-style"); - registerDataType((obj) -> { - Map data = MiscUtils.castToMap(obj, false); - return new EquippableModifier<>(EquipmentData.fromMap(data)); - }, "equippable"); - registerDataType((obj) -> { - String id = obj.toString(); - return new ItemModelModifier<>(Key.of(id)); - }, "item-model"); + // 抛出异常 + collector.throwIfPresent(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index f1692ece7..ee799b262 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.attribute.AttributeModifier; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; @@ -119,6 +120,8 @@ public interface Item { Optional> loreComponent(); + Item attributeModifiers(List modifiers); + Optional jukeboxSong(); Item jukeboxSong(JukeboxPlayable song); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemDataModifierFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemDataModifierFactory.java new file mode 100644 index 000000000..446ed2272 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemDataModifierFactory.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.item; + +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; + +public interface ItemDataModifierFactory { + + ItemDataModifier create(Object arg); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index 70d734922..f88830935 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.attribute.AttributeModifier; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; @@ -215,4 +216,6 @@ public abstract class ItemFactory, I> { protected abstract boolean isDyeItem(W item); protected abstract Optional dyeColor(W item); + + protected abstract void attributeModifiers(W item, List modifiers); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index d88e2d5d3..9b82c4f3d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.equipment.Equipment; -import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.model.ModernItemModel; @@ -18,14 +17,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Function; public interface ItemManager extends Manageable, ModelGenerator { - void registerDataType(Function> factory, String... alias); - - Function> getDataType(String key); - Map equipments(); ConfigParser[] parsers(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentsModifier.java similarity index 59% rename from core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentModifier.java rename to core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentsModifier.java index 63628171d..33f4bb98f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentsModifier.java @@ -3,7 +3,11 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.StringTag; @@ -12,17 +16,22 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -public class ArgumentModifier implements ItemDataModifier { +public class ArgumentsModifier implements ItemDataModifier { + public static final Factory FACTORY = new Factory<>(); public static final String ARGUMENTS_TAG = "craftengine:arguments"; private final Map arguments; - public ArgumentModifier(Map arguments) { + public ArgumentsModifier(Map arguments) { this.arguments = arguments; } + public Map arguments() { + return arguments; + } + @Override - public String name() { - return "arguments"; + public Key type() { + return ItemDataModifiers.ARGUMENTS; } @Override @@ -44,4 +53,17 @@ public class ArgumentModifier implements ItemDataModifier { } return item; } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "arguments"); + Map arguments = new HashMap<>(); + for (Map.Entry entry : data.entrySet()) { + arguments.put(entry.getKey(), TextProviders.fromString(entry.getValue().toString())); + } + return new ArgumentsModifier<>(arguments); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/AttributeModifiersModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/AttributeModifiersModifier.java index 1bc71cff2..eaa06e44f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/AttributeModifiersModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/AttributeModifiersModifier.java @@ -6,19 +6,14 @@ import net.momirealms.craftengine.core.attribute.Attributes1_21; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.UUIDUtils; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.ListTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.util.*; +import org.jetbrains.annotations.Nullable; -import java.nio.charset.StandardCharsets; import java.util.*; -public class AttributeModifiersModifier implements ItemDataModifier { +public class AttributeModifiersModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); public static final Map CONVERTOR = new HashMap<>(); static { @@ -102,89 +97,64 @@ public class AttributeModifiersModifier implements ItemDataModifier { } @Override - public String name() { - return "attribute-modifiers"; + public Key type() { + return ItemDataModifiers.ATTRIBUTE_MODIFIERS; } - private static Object previous; - @Override public Item apply(Item item, ItemBuildContext context) { - if (VersionHelper.isOrAbove1_21_5()) { - ListTag modifiers = new ListTag(); - for (AttributeModifier modifier : this.modifiers) { - CompoundTag modifierTag = new CompoundTag(); - modifierTag.putString("type", modifier.type()); - modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); - modifierTag.putString("id", modifier.id().toString()); - modifierTag.putDouble("amount", modifier.amount()); - modifierTag.putString("operation", modifier.operation().id()); - AttributeModifier.Display display = modifier.display(); - if (VersionHelper.isOrAbove1_21_6() && display != null) { - CompoundTag displayTag = new CompoundTag(); - AttributeModifier.Display.Type displayType = display.type(); - displayTag.putString("type", displayType.name().toLowerCase(Locale.ENGLISH)); - if (displayType == AttributeModifier.Display.Type.OVERRIDE) { - displayTag.put("value", AdventureHelper.componentToTag(AdventureHelper.miniMessage().deserialize(display.value(), context.tagResolvers()))); - } - modifierTag.put("display", displayTag); - } - modifiers.add(modifierTag); - } - item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, modifiers); - } else if (VersionHelper.isOrAbove1_20_5()) { - CompoundTag compoundTag = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS)).orElseGet(CompoundTag::new); - ListTag modifiers = new ListTag(); - compoundTag.put("modifiers", modifiers); - for (AttributeModifier modifier : this.modifiers) { - CompoundTag modifierTag = new CompoundTag(); - modifierTag.putString("type", modifier.type()); - modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); - if (VersionHelper.isOrAbove1_21()) { - modifierTag.putString("id", modifier.id().toString()); - } else { - modifierTag.putIntArray("uuid", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8)))); - modifierTag.putString("name", modifier.id().toString()); - } - modifierTag.putDouble("amount", modifier.amount()); - modifierTag.putString("operation", modifier.operation().id()); - modifiers.add(modifierTag); - } - item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, compoundTag); - } else { - ListTag listTag = new ListTag(); - for (AttributeModifier modifier : this.modifiers) { - CompoundTag modifierTag = new CompoundTag(); - modifierTag.putString("AttributeName", modifier.type()); - modifierTag.putString("Name", modifier.id().toString()); - modifierTag.putString("Slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); - modifierTag.putInt("Operation", modifier.operation().ordinal()); - modifierTag.putDouble("Amount", modifier.amount()); - modifierTag.putIntArray("UUID", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8)))); - listTag.add(modifierTag); - } - item.setTag(listTag, "AttributeModifiers"); - } - return item; + return item.attributeModifiers(this.modifiers); } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS); - if (previous != null) { - networkData.put(ComponentKeys.ATTRIBUTE_MODIFIERS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.ATTRIBUTE_MODIFIERS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("AttributeModifiers"); - if (previous != null) { - networkData.put("AttributeModifiers", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("AttributeModifiers", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.ATTRIBUTE_MODIFIERS; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"AttributeModifiers"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "AttributeModifiers"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + MutableInt mutableInt = new MutableInt(0); + List attributeModifiers = ResourceConfigUtils.parseConfigAsList(arg, (map) -> { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.data.attribute_modifiers.missing_type"); + Key nativeType = AttributeModifiersModifier.getNativeAttributeName(Key.of(type)); + AttributeModifier.Slot slot = AttributeModifier.Slot.valueOf(map.getOrDefault("slot", "any").toString().toUpperCase(Locale.ENGLISH)); + Key id = Optional.ofNullable(map.get("id")).map(String::valueOf).map(Key::of).orElseGet(() -> { + mutableInt.add(1); + return Key.of("craftengine", "modifier_" + mutableInt.intValue()); + }); + double amount = ResourceConfigUtils.getAsDouble( + ResourceConfigUtils.requireNonNullOrThrow(map.get("amount"), "warning.config.item.data.attribute_modifiers.missing_amount"), "amount" + ); + AttributeModifier.Operation operation = AttributeModifier.Operation.valueOf( + ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("operation"), "warning.config.item.data.attribute_modifiers.missing_operation").toUpperCase(Locale.ENGLISH) + ); + AttributeModifier.Display display = null; + if (VersionHelper.isOrAbove1_21_6() && map.containsKey("display")) { + Map displayMap = MiscUtils.castToMap(map.get("display"), false); + AttributeModifier.Display.Type displayType = AttributeModifier.Display.Type.valueOf(ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("type"), "warning.config.item.data.attribute_modifiers.display.missing_type").toUpperCase(Locale.ENGLISH)); + if (displayType == AttributeModifier.Display.Type.OVERRIDE) { + String miniMessageValue = ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("value"), "warning.config.item.data.attribute_modifiers.display.missing_value"); + display = new AttributeModifier.Display(displayType, AdventureHelper.miniMessage().deserialize(miniMessageValue)); + } else { + display = new AttributeModifier.Display(displayType, null); + } + } + return new AttributeModifier(nativeType.value(), slot, id, + amount, operation, display); + }); + return new AttributeModifiersModifier<>(attributeModifiers); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentsModifier.java similarity index 80% rename from core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java rename to core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentsModifier.java index 3dc223ca3..7e822a08d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentsModifier.java @@ -1,14 +1,12 @@ package net.momirealms.craftengine.core.item.modifier; import com.google.gson.JsonElement; -import net.momirealms.craftengine.core.item.ComponentKeys; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Pair; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -16,11 +14,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -public class ComponentModifier implements ItemDataModifier { +public class ComponentsModifier implements ItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final List> arguments; private CompoundTag customData = null; - public ComponentModifier(Map arguments) { + public ComponentsModifier(Map arguments) { List> pairs = new ArrayList<>(arguments.size()); for (Map.Entry entry : arguments.entrySet()) { Key key = Key.of(entry.getKey()); @@ -33,7 +32,7 @@ public class ComponentModifier implements ItemDataModifier { this.arguments = pairs; } - public List> arguments() { + public List> components() { return arguments; } @@ -49,8 +48,8 @@ public class ComponentModifier implements ItemDataModifier { } @Override - public String name() { - return "components"; + public Key type() { + return ItemDataModifiers.COMPONENTS; } @Override @@ -84,4 +83,13 @@ public class ComponentModifier implements ItemDataModifier { } return item; } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "components"); + return new ComponentsModifier<>(data); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java index f76bb1c78..9d1c68671 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java @@ -3,21 +3,26 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -public class CustomModelDataModifier implements ItemDataModifier { +public class CustomModelDataModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final int argument; public CustomModelDataModifier(int argument) { this.argument = argument; } + public int customModelData() { + return this.argument; + } + @Override - public String name() { - return "custom-model-data"; + public Key type() { + return ItemDataModifiers.CUSTOM_MODEL_DATA; } @Override @@ -27,22 +32,26 @@ public class CustomModelDataModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.CUSTOM_MODEL_DATA); - if (previous != null) { - networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("CustomModelData"); - if (previous != null) { - networkData.put("CustomModelData", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("CustomModelData", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.CUSTOM_MODEL_DATA; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"CustomModelData"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "CustomModelData"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + int customModelData = ResourceConfigUtils.getAsInt(arg, "custom-model-data"); + return new CustomModelDataModifier<>(customModelData); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index ecbbbe33a..8989c2225 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java @@ -3,14 +3,14 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; -public class CustomNameModifier implements ItemDataModifier { +public class CustomNameModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final String argument; public CustomNameModifier(String argument) { @@ -25,9 +25,13 @@ public class CustomNameModifier implements ItemDataModifier { } } + public String customName() { + return argument; + } + @Override - public String name() { - return "custom-name"; + public Key type() { + return ItemDataModifiers.CUSTOM_NAME; } @Override @@ -37,22 +41,26 @@ public class CustomNameModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.CUSTOM_NAME); - if (previous != null) { - networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("display", "Name"); - if (previous != null) { - networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.CUSTOM_NAME; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"display", "Name"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "display.Name"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + String name = arg.toString(); + return new CustomNameModifier<>(name); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java index f96536406..2ce36e797 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java @@ -3,47 +3,60 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.util.Color; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; -public class DyedColorModifier implements ItemDataModifier { +public class DyedColorModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final Color color; public DyedColorModifier(Color color) { this.color = color; } + public Color dyedColor() { + return color; + } + @Override - public String name() { - return "dyed-color"; + public Key type() { + return ItemDataModifiers.DYED_COLOR; } @Override public Item apply(Item item, ItemBuildContext context) { - item.dyedColor(this.color); - return item; + return item.dyedColor(this.color); } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.DYED_COLOR); - if (previous != null) { - networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.DYED_COLOR; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"display", "color"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "display.color"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + if (arg instanceof Integer integer) { + return new DyedColorModifier<>(Color.fromDecimal(integer)); } else { - networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("display", "color"); - if (previous != null) { - networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + Vector3f vector3f = MiscUtils.getAsVector3f(arg, "dyed-color"); + return new DyedColorModifier<>(Color.fromVector3f(vector3f)); } } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java deleted file mode 100644 index 9168de84a..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java +++ /dev/null @@ -1,70 +0,0 @@ -package net.momirealms.craftengine.core.item.modifier; - -import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.data.Enchantment; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; - -import java.util.List; - -public class EnchantmentModifier implements ItemDataModifier { - private final List enchantments; - - public EnchantmentModifier(List enchantments) { - this.enchantments = enchantments; - } - - @Override - public String name() { - return "enchantment"; - } - - @Override - public Item apply(Item item, ItemBuildContext context) { - if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { - item.setStoredEnchantments(this.enchantments); - } else { - item.setEnchantments(this.enchantments); - } - return item; - } - - @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.STORED_ENCHANTMENTS); - if (previous != null) { - networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("StoredEnchantments"); - if (previous != null) { - networkData.put("StoredEnchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("StoredEnchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } - } else { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.ENCHANTMENTS); - if (previous != null) { - networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("Enchantments"); - if (previous != null) { - networkData.put("Enchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("Enchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } - } - return item; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java new file mode 100644 index 000000000..8dbb7a591 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java @@ -0,0 +1,68 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.*; +import net.momirealms.craftengine.core.item.data.Enchantment; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class EnchantmentsModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); + private final List enchantments; + + public EnchantmentsModifier(List enchantments) { + this.enchantments = enchantments; + } + + public List enchantments() { + return enchantments; + } + + @Override + public Key type() { + return ItemDataModifiers.ENCHANTMENTS; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { + return item.setStoredEnchantments(this.enchantments); + } else { + return item.setEnchantments(this.enchantments); + } + } + + @Override + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK) ? ComponentKeys.STORED_ENCHANTMENTS : ComponentKeys.ENCHANTMENTS; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK) ? new Object[]{"StoredEnchantments"} : new Object[]{"Enchantments"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK) ? "StoredEnchantments" : "Enchantments"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "enchantments"); + List enchantments = new ArrayList<>(); + for (Map.Entry e : data.entrySet()) { + if (e.getValue() instanceof Number number) { + enchantments.add(new Enchantment(Key.of(e.getKey()), number.intValue())); + } + } + return new EnchantmentsModifier<>(enchantments); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableAssetIdModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableAssetIdModifier.java index 48630e358..d6cb67ac6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableAssetIdModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableAssetIdModifier.java @@ -3,24 +3,26 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; import java.util.Optional; -public class EquippableAssetIdModifier implements ItemDataModifier { +public class EquippableAssetIdModifier implements SimpleNetworkItemDataModifier { private final Key assetId; public EquippableAssetIdModifier(Key assetsId) { this.assetId = assetsId; } + public Key assetId() { + return assetId; + } + @Override - public String name() { - return "equippable-asset-id"; + public Key type() { + return ItemDataModifiers.EQUIPPABLE_ASSET_ID; } @Override @@ -39,13 +41,7 @@ public class EquippableAssetIdModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.EQUIPPABLE); - if (previous != null) { - networkData.put(ComponentKeys.EQUIPPABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.EQUIPPABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - return item; + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.EQUIPPABLE; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java index 9851c1141..6570920da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java @@ -1,24 +1,49 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.setting.EquipmentData; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -public class EquippableModifier implements ItemDataModifier { +import java.util.Map; + +public class EquippableModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final EquipmentData data; public EquippableModifier(EquipmentData data) { this.data = data; } + public EquipmentData data() { + return data; + } + @Override - public String name() { - return "equippable"; + public Key type() { + return ItemDataModifiers.EQUIPPABLE; } @Override public Item apply(Item item, ItemBuildContext context) { - item.equippable(this.data); - return item; + return item.equippable(this.data); + } + + @Override + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.EQUIPPABLE; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "equippable"); + return new EquippableModifier<>(EquipmentData.fromMap(data)); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java index 3acc923b8..a424feb2a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java @@ -3,9 +3,17 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ExternalItemSource; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Locale; +import java.util.Map; public class ExternalModifier implements ItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final String id; private final ExternalItemSource provider; @@ -14,9 +22,17 @@ public class ExternalModifier implements ItemDataModifier { this.provider = provider; } + public String id() { + return id; + } + + public ExternalItemSource source() { + return provider; + } + @Override - public String name() { - return "external"; + public Key type() { + return ItemDataModifiers.EXTERNAL; } @SuppressWarnings("unchecked") @@ -31,4 +47,17 @@ public class ExternalModifier implements ItemDataModifier { item.merge(anotherWrapped); return item; } + + public static class Factory implements ItemDataModifierFactory { + + @SuppressWarnings("unchecked") + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "external"); + String plugin = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(data, "plugin", "source"), "warning.config.item.data.external.missing_source"); + String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(data.get("id"), "warning.config.item.data.external.missing_id"); + ExternalItemSource provider = (ExternalItemSource) CraftEngine.instance().itemManager().getExternalItemSource(plugin.toLowerCase(Locale.ENGLISH)); + return new ExternalModifier<>(id, ResourceConfigUtils.requireNonNullOrThrow(provider, () -> new LocalizedResourceConfigException("warning.config.item.data.external.invalid_source", plugin))); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/FoodModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/FoodModifier.java index 4ab82b684..42fcb7f65 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/FoodModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/FoodModifier.java @@ -3,13 +3,15 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; import java.util.Map; -public class FoodModifier implements ItemDataModifier { +public class FoodModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final int nutrition; private final float saturation; private final boolean canAlwaysEat; @@ -20,9 +22,21 @@ public class FoodModifier implements ItemDataModifier { this.saturation = saturation; } + public boolean canAlwaysEat() { + return canAlwaysEat; + } + + public int nutrition() { + return nutrition; + } + + public float saturation() { + return saturation; + } + @Override - public String name() { - return "food"; + public Key type() { + return ItemDataModifiers.FOOD; } @Override @@ -36,13 +50,18 @@ public class FoodModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.FOOD); - if (previous != null) { - networkData.put(ComponentKeys.FOOD.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.FOOD.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.FOOD; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "food"); + int nutrition = ResourceConfigUtils.getAsInt(data.get("nutrition"), "nutrition"); + float saturation = ResourceConfigUtils.getAsFloat(data.get("saturation"), "saturation"); + return new FoodModifier<>(nutrition, saturation, ResourceConfigUtils.getAsBoolean(data.getOrDefault("can-always-eat", false), "can-always-eat")); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java index 56fa6eea9..e2b229923 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java @@ -1,10 +1,7 @@ package net.momirealms.craftengine.core.item.modifier; import com.google.common.collect.ImmutableMap; -import net.momirealms.craftengine.core.item.ComponentKeys; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -19,6 +16,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; public class HideTooltipModifier implements ItemDataModifier { + public static final Factory FACTORY = new Factory<>(); public static final Map TO_LEGACY; public static final List COMPONENTS = List.of( ComponentKeys.UNBREAKABLE, @@ -127,8 +125,8 @@ public class HideTooltipModifier implements ItemDataModifier { } @Override - public String name() { - return "hide-tooltip"; + public Key type() { + return ItemDataModifiers.HIDE_TOOLTIP; } public interface Applier { @@ -233,4 +231,13 @@ public class HideTooltipModifier implements ItemDataModifier { } } } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + List components = MiscUtils.getAsStringList(arg).stream().map(Key::of).toList(); + return new HideTooltipModifier<>(components); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java index 690236b87..a262ac971 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java @@ -12,9 +12,13 @@ public class IdModifier implements ItemDataModifier { this.argument = argument; } + public Key identifier() { + return argument; + } + @Override - public String name() { - return "id"; + public Key type() { + return ItemDataModifiers.ID; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java index 2ffe87f59..6a39cf797 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java @@ -2,11 +2,12 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; public interface ItemDataModifier { - String name(); + Key type(); Item apply(Item item, ItemBuildContext context); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java new file mode 100644 index 000000000..f120401e8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java @@ -0,0 +1,88 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.item.modifier.lore.DynamicLoreModifier; +import net.momirealms.craftengine.core.item.modifier.lore.LoreModifier; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceKey; +import net.momirealms.craftengine.core.util.VersionHelper; + +public final class ItemDataModifiers { + private ItemDataModifiers() {} + + public static final Key ITEM_MODEL = Key.of("craftengine:item-model"); + public static final Key ID = Key.of("craftengine:id"); + public static final Key HIDE_TOOLTIP = Key.of("craftengine:hide-tooltip"); + public static final Key FOOD = Key.of("craftengine:food"); + public static final Key EXTERNAL = Key.of("craftengine:external"); + public static final Key EQUIPPABLE = Key.of("craftengine:equippable"); + public static final Key EQUIPPABLE_ASSET_ID = Key.of("craftengine:equippable-asset-id"); + public static final Key ENCHANTMENT = Key.of("craftengine:enchantment"); + public static final Key ENCHANTMENTS = Key.of("craftengine:enchantments"); + public static final Key DYED_COLOR = Key.of("craftengine:dyed-color"); + public static final Key DISPLAY_NAME = Key.of("craftengine:display-name"); + public static final Key CUSTOM_NAME = Key.of("craftengine:custom-name"); + public static final Key CUSTOM_MODEL_DATA = Key.of("craftengine:custom-model-data"); + public static final Key COMPONENTS = Key.of("craftengine:components"); + public static final Key ATTRIBUTE_MODIFIERS = Key.of("craftengine:attribute-modifiers"); + public static final Key ATTRIBUTES = Key.of("craftengine:attributes"); + public static final Key ARGUMENTS = Key.of("craftengine:arguments"); + public static final Key ITEM_NAME = Key.of("craftengine:item-name"); + public static final Key JUKEBOX_PLAYABLE = Key.of("craftengine:jukebox-playable"); + public static final Key REMOVE_COMPONENTS = Key.of("craftengine:remove-components"); + public static final Key TAGS = Key.of("craftengine:tags"); + public static final Key NBT = Key.of("craftengine:nbt"); + public static final Key TOOLTIP_STYLE = Key.of("craftengine:tooltip-style"); + public static final Key TRIM = Key.of("craftengine:trim"); + public static final Key LORE = Key.of("craftengine:lore"); + public static final Key UNBREAKABLE = Key.of("craftengine:unbreakable"); + public static final Key DYNAMIC_LORE = Key.of("craftengine:dynamic-lore"); + + public static void register(Key key, ItemDataModifierFactory factory) { + ((WritableRegistry>) BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY) + .register(ResourceKey.create(Registries.ITEM_DATA_MODIFIER_FACTORY.location(), key), factory); + } + + public static void init() {} + + static { + register(EXTERNAL, ExternalModifier.FACTORY); + register(LORE, LoreModifier.FACTORY); + register(DYNAMIC_LORE, DynamicLoreModifier.FACTORY); + register(DYED_COLOR, DyedColorModifier.FACTORY); + register(TAGS, TagsModifier.FACTORY); + register(NBT, TagsModifier.FACTORY); + register(ATTRIBUTE_MODIFIERS, AttributeModifiersModifier.FACTORY); + register(ATTRIBUTES, AttributeModifiersModifier.FACTORY); + register(CUSTOM_MODEL_DATA, CustomModelDataModifier.FACTORY); + register(UNBREAKABLE, UnbreakableModifier.FACTORY); + register(ENCHANTMENT, EnchantmentsModifier.FACTORY); + register(ENCHANTMENTS, EnchantmentsModifier.FACTORY); + register(TRIM, TrimModifier.FACTORY); + register(HIDE_TOOLTIP, HideTooltipModifier.FACTORY); + register(ARGUMENTS, ArgumentsModifier.FACTORY); + if (VersionHelper.isOrAbove1_20_5()) { + register(CUSTOM_NAME, CustomNameModifier.FACTORY); + register(ITEM_NAME, ItemNameModifier.FACTORY); + register(DISPLAY_NAME, ItemNameModifier.FACTORY); + register(COMPONENTS, ComponentsModifier.FACTORY); + register(REMOVE_COMPONENTS, RemoveComponentModifier.FACTORY); + register(FOOD, FoodModifier.FACTORY); + } else { + register(CUSTOM_NAME, CustomNameModifier.FACTORY); + register(ITEM_NAME, CustomNameModifier.FACTORY); + register(DISPLAY_NAME, CustomNameModifier.FACTORY); + } + if (VersionHelper.isOrAbove1_21()) { + register(JUKEBOX_PLAYABLE, JukeboxSongModifier.FACTORY); + } + if (VersionHelper.isOrAbove1_21_2()) { + register(TOOLTIP_STYLE, TooltipStyleModifier.FACTORY); + register(ITEM_MODEL, ItemModelModifier.FACTORY); + register(EQUIPPABLE, EquippableModifier.FACTORY); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java index 319cacc13..c83be84d6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java @@ -3,37 +3,43 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; -public class ItemModelModifier implements ItemDataModifier { +public class ItemModelModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final Key data; public ItemModelModifier(Key data) { this.data = data; } + public Key data() { + return data; + } + @Override - public String name() { - return "item-model"; + public Key type() { + return ItemDataModifiers.ITEM_MODEL; } @Override public Item apply(Item item, ItemBuildContext context) { - item.itemModel(this.data.toString()); - return item; + return item.itemModel(this.data.asString()); } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.ITEM_MODEL); - if (previous != null) { - networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.ITEM_MODEL; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + String id = arg.toString(); + return new ItemModelModifier<>(Key.of(id)); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java index 63cfac93f..20728b979 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java @@ -3,22 +3,26 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; -public class ItemNameModifier implements ItemDataModifier { +public class ItemNameModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final String argument; public ItemNameModifier(String argument) { this.argument = argument; } + public String itemName() { + return argument; + } + @Override - public String name() { - return "item-name"; + public Key type() { + return ItemDataModifiers.ITEM_NAME; } @Override @@ -28,22 +32,26 @@ public class ItemNameModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.ITEM_NAME); - if (previous != null) { - networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("display", "Name"); - if (previous != null) { - networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.ITEM_NAME; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"display", "Name"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "display.Name"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + String name = arg.toString(); + return new ItemNameModifier<>(name); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java index 6ccd1ec12..7702865f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java @@ -2,18 +2,25 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; +import net.momirealms.craftengine.core.util.Key; public class JukeboxSongModifier implements ItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final JukeboxPlayable song; public JukeboxSongModifier(JukeboxPlayable song) { this.song = song; } + public JukeboxPlayable song() { + return song; + } + @Override - public String name() { - return "jukebox-playable"; + public Key type() { + return ItemDataModifiers.JUKEBOX_PLAYABLE; } @Override @@ -21,4 +28,13 @@ public class JukeboxSongModifier implements ItemDataModifier { item.jukeboxSong(this.song); return item; } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + String song = arg.toString(); + return new JukeboxSongModifier<>(new JukeboxPlayable(song, true)); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java index 324db069b..a7ffd1c0b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java @@ -2,7 +2,10 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -10,19 +13,20 @@ import java.util.Collections; import java.util.List; public class RemoveComponentModifier implements ItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final List arguments; public RemoveComponentModifier(List arguments) { this.arguments = arguments; } - public List arguments() { + public List components() { return Collections.unmodifiableList(this.arguments); } @Override - public String name() { - return "remove-components"; + public Key type() { + return ItemDataModifiers.REMOVE_COMPONENTS; } @Override @@ -43,4 +47,13 @@ public class RemoveComponentModifier implements ItemDataModifier { } return item; } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + List data = MiscUtils.getAsStringList(arg); + return new RemoveComponentModifier<>(data); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/SimpleNetworkItemDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/SimpleNetworkItemDataModifier.java new file mode 100644 index 000000000..2d5664ff0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/SimpleNetworkItemDataModifier.java @@ -0,0 +1,61 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; + +public interface SimpleNetworkItemDataModifier extends ItemDataModifier { + + @Override + default Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.COMPONENT_RELEASE) { + Key componentType= componentType(item, context); + if (componentType != null) { + Tag previous = item.getSparrowNBTComponent(componentType); + if (previous != null) { + networkData.put(componentType.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(componentType.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } else { + Object[] path = nbtPath(item, context); + if (path != null) { + Tag previous = item.getTag(path); + if (previous != null) { + networkData.put(nbtPathString(item, context), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(nbtPathString(item, context), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } + return item; + } + + @Nullable + default Key componentType(Item item, ItemBuildContext context) { + return null; + } + + @Nullable + default Object[] nbtPath(Item item, ItemBuildContext context) { + return null; + } + + default String nbtPathString(Item item, ItemBuildContext context) { + Object[] path = nbtPath(item, context); + if (path != null && path.length > 0) { + StringBuilder builder = new StringBuilder(); + for (Object object : path) { + builder.append(object.toString()); + } + return builder.toString(); + } + return ""; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java index 16a8ec444..6995c87a2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java @@ -1,12 +1,7 @@ package net.momirealms.craftengine.core.item.modifier; -import net.momirealms.craftengine.core.item.ComponentKeys; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.TypeUtils; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.item.*; +import net.momirealms.craftengine.core.util.*; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -14,19 +9,20 @@ import java.util.LinkedHashMap; import java.util.Map; public class TagsModifier implements ItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final Map arguments; public TagsModifier(Map arguments) { this.arguments = mapToMap(arguments); } - public Map arguments() { + public Map tags() { return arguments; } @Override - public String name() { - return "tags"; + public Key type() { + return ItemDataModifiers.TAGS; } @Override @@ -135,4 +131,12 @@ public class TagsModifier implements ItemDataModifier { private record ParsedValue(boolean success, Object result) { static final ParsedValue FAILURE = new ParsedValue(false, null); } + + public static class Factory implements ItemDataModifierFactory { + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "nbt"); + return new TagsModifier<>(data); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java index ac3a38114..573c484f5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java @@ -3,21 +3,25 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; -public class TooltipStyleModifier implements ItemDataModifier { +public class TooltipStyleModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final Key argument; public TooltipStyleModifier(Key argument) { this.argument = argument; } + public Key tooltipStyle() { + return this.argument; + } + @Override - public String name() { - return "tooltip-style"; + public Key type() { + return ItemDataModifiers.TOOLTIP_STYLE; } @Override @@ -27,13 +31,16 @@ public class TooltipStyleModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.TOOLTIP_STYLE); - if (previous != null) { - networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.TOOLTIP_STYLE; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + String id = arg.toString(); + return new TooltipStyleModifier<>(Key.of(id)); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java index 3a5a32a56..82c7a537e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java @@ -3,14 +3,17 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.data.Trim; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -public class TrimModifier implements ItemDataModifier { +import java.util.Locale; +import java.util.Map; + +public class TrimModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final Key material; private final Key pattern; @@ -19,34 +22,47 @@ public class TrimModifier implements ItemDataModifier { this.pattern = pattern; } + public Key material() { + return material; + } + + public Key pattern() { + return pattern; + } + @Override - public String name() { - return "trim"; + public Key type() { + return ItemDataModifiers.TRIM; } @Override public Item apply(Item item, ItemBuildContext context) { - item.trim(new Trim(this.pattern, this.material)); - return item; + return item.trim(new Trim(this.pattern, this.material)); } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.TRIM); - if (previous != null) { - networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("Trim"); - if (previous != null) { - networkData.put("Trim", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("Trim", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.TRIM; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"Trim"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "Trim"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "trim"); + String material = data.get("material").toString().toLowerCase(Locale.ENGLISH); + String pattern = data.get("pattern").toString().toLowerCase(Locale.ENGLISH); + return new TrimModifier<>(Key.of(material), Key.of(pattern)); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java index b1be281a0..e2799c35e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java @@ -3,21 +3,26 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -public class UnbreakableModifier implements ItemDataModifier { +public class UnbreakableModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); private final boolean argument; public UnbreakableModifier(boolean argument) { this.argument = argument; } + public boolean unbreakable() { + return argument; + } + @Override - public String name() { - return "unbreakable"; + public Key type() { + return ItemDataModifiers.UNBREAKABLE; } @Override @@ -27,22 +32,26 @@ public class UnbreakableModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.UNBREAKABLE); - if (previous != null) { - networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("Unbreakable"); - if (previous != null) { - networkData.put("Unbreakable", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("Unbreakable", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.UNBREAKABLE; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"Unbreakable"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "Unbreakable"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + boolean value = ResourceConfigUtils.getAsBoolean(arg, "unbreakable"); + return new UnbreakableModifier<>(value); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java index 5f36228d8..8f60c4cca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java @@ -3,16 +3,18 @@ package net.momirealms.craftengine.core.item.modifier.lore; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifiers; +import net.momirealms.craftengine.core.item.modifier.SimpleNetworkItemDataModifier; +import net.momirealms.craftengine.core.util.Key; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; -public final class DynamicLoreModifier implements ItemDataModifier { +public final class DynamicLoreModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); public static final String CONTEXT_TAG_KEY = "craftengine:display_context"; private final Map> displayContexts; private final LoreModifier defaultModifier; @@ -27,8 +29,8 @@ public final class DynamicLoreModifier implements ItemDataModifier { } @Override - public String name() { - return "dynamic-lore"; + public Key type() { + return ItemDataModifiers.DYNAMIC_LORE; } @Override @@ -42,22 +44,30 @@ public final class DynamicLoreModifier implements ItemDataModifier { } @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE); - if (previous != null) { - networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("display", "Lore"); - if (previous != null) { - networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + public Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.LORE; + } + + @Override + public Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"display", "Lore"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "display.Lore"; + } + + public static class Factory implements ItemDataModifierFactory { + @Override + public ItemDataModifier create(Object arg) { + Map> dynamicLore = new LinkedHashMap<>(); + if (arg instanceof Map map) { + for (Map.Entry entry : map.entrySet()) { + dynamicLore.put(entry.getKey().toString(), LoreModifier.createLoreModifier(entry.getValue())); + } } + return new DynamicLoreModifier<>(dynamicLore); } - return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java index 8e998115d..6e5f3411a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java @@ -4,37 +4,51 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifiers; +import net.momirealms.craftengine.core.item.modifier.SimpleNetworkItemDataModifier; +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.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.stream.Stream; -public sealed interface LoreModifier extends ItemDataModifier +public sealed interface LoreModifier extends SimpleNetworkItemDataModifier permits LoreModifier.EmptyLoreModifier, LoreModifier.CompositeLoreModifier, LoreModifier.DoubleLoreModifier, LoreModifier.SingleLoreModifier { + Factory FACTORY = new Factory<>(); @Override - default String name() { - return "lore"; + default Key type() { + return ItemDataModifiers.LORE; } @Override - default Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE); - if (previous != null) networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - else networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } else { - Tag previous = item.getTag("display", "Lore"); - if (previous != null) networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - else networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + @Nullable + default Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.LORE; + } + + @Override + @Nullable + default Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"display", "Lore"}; + } + + @Override + default String nbtPathString(Item item, ItemBuildContext context) { + return "display.Lore"; + } + + List lore(); + + class Factory implements ItemDataModifierFactory { + @Override + public ItemDataModifier create(Object arg) { + return createLoreModifier(arg); } - return item; } static LoreModifier createLoreModifier(Object arg) { @@ -78,6 +92,11 @@ public sealed interface LoreModifier extends ItemDataModifier public Item apply(Item item, ItemBuildContext context) { return item; } + + @Override + public List lore() { + return List.of(); + } } non-sealed class SingleLoreModifier implements LoreModifier { @@ -92,6 +111,11 @@ public sealed interface LoreModifier extends ItemDataModifier item.loreComponent(this.modification.parseAsList(context)); return item; } + + @Override + public List lore() { + return List.of(modification); + } } non-sealed class DoubleLoreModifier implements LoreModifier { @@ -108,6 +132,11 @@ public sealed interface LoreModifier extends ItemDataModifier item.loreComponent(this.modification2.apply(this.modification1.apply(Stream.empty(), context), context).toList()); return item; } + + @Override + public List lore() { + return List.of(modification1, modification2); + } } non-sealed class CompositeLoreModifier implements LoreModifier { @@ -122,5 +151,10 @@ public sealed interface LoreModifier extends ItemDataModifier item.loreComponent(Arrays.stream(this.modifications).reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); return item; } + + @Override + public List lore() { + return Arrays.asList(modifications); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java index ea35480b2..0afc9ab64 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.BuildableItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; @@ -33,9 +32,8 @@ public record CustomRecipeResult(BuildableItem item, int count, PostProces registerPostProcessorType(Key.of("apply_data"), args -> { List> modifiers = new ArrayList<>(); for (Map.Entry entry : args.entrySet()) { - Optional.ofNullable(CraftEngine.instance().itemManager().getDataType(entry.getKey())).ifPresent(it -> { - modifiers.add(it.apply(entry.getValue())); - }); + Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), "craftengine"))) + .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); } return new ApplyItemDataProcessor<>(modifiers.toArray(new ItemDataModifier[0])); }); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index f8bb24094..478d3e5bd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -591,11 +591,7 @@ public abstract class AbstractPackManager implements PackManager { } } } catch (LocalizedException e) { - if (e instanceof LocalizedResourceConfigException exception) { - exception.setPath(cached.filePath()); - exception.setId(cached.prefix() + "." + key); - } - TranslationManager.instance().log(e.node(), e.arguments()); + printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key); } catch (Exception e) { this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "." + key + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(configEntry.getValue()), e); } @@ -607,6 +603,19 @@ public abstract class AbstractPackManager implements PackManager { } } + private void printWarningRecursively(LocalizedException e, Path path, String prefix) { + for (Throwable t : e.getSuppressed()) { + if (t instanceof LocalizedException suppressed) { + printWarningRecursively(suppressed, path, prefix); + } + } + if (e instanceof LocalizedResourceConfigException exception) { + exception.setPath(path); + exception.setId(prefix); + } + TranslationManager.instance().log(e.node(), e.arguments()); + } + private void processConfigEntry(Map.Entry entry, Path path, Pack pack, BiConsumer callback) { if (entry.getValue() instanceof Map typeSections0) { String key = entry.getKey(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java index b4662a547..d636f5268 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java @@ -31,6 +31,10 @@ public class FixedNumberProvider implements NumberProvider { return NumberProviders.FIXED; } + public static FixedNumberProvider of(final double value) { + return new FixedNumberProvider(value); + } + public static class FactoryImpl implements NumberProviderFactory { @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index a88ef798b..a864ca257 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; @@ -42,6 +43,7 @@ import net.momirealms.craftengine.core.util.ResourceKey; public class BuiltInRegistries { public static final Registry BLOCK = createDynamicBoundRegistry(Registries.BLOCK); public static final Registry BLOCK_BEHAVIOR_FACTORY = createConstantBoundRegistry(Registries.BLOCK_BEHAVIOR_FACTORY); + public static final Registry> ITEM_DATA_MODIFIER_FACTORY = createConstantBoundRegistry(Registries.ITEM_DATA_MODIFIER_FACTORY); public static final Registry ITEM_BEHAVIOR_FACTORY = createConstantBoundRegistry(Registries.ITEM_BEHAVIOR_FACTORY); public static final Registry PROPERTY_FACTORY = createConstantBoundRegistry(Registries.PROPERTY_FACTORY); public static final Registry> LOOT_FUNCTION_FACTORY = createConstantBoundRegistry(Registries.LOOT_FUNCTION_FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 382277302..fe447e488 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; @@ -43,6 +44,7 @@ import net.momirealms.craftengine.core.util.ResourceKey; public class Registries { public static final Key ROOT_REGISTRY = Key.withDefaultNamespace("root"); public static final ResourceKey> BLOCK = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("block")); + public static final ResourceKey>> ITEM_DATA_MODIFIER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_data_modifier_factory")); public static final ResourceKey> PROPERTY_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("property_factory")); public static final ResourceKey> BLOCK_BEHAVIOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("block_behavior_factory")); public static final ResourceKey> ITEM_BEHAVIOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_behavior_factory")); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ExceptionCollector.java b/core/src/main/java/net/momirealms/craftengine/core/util/ExceptionCollector.java index 868df2a03..f7a678862 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ExceptionCollector.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ExceptionCollector.java @@ -19,5 +19,10 @@ public class ExceptionCollector { throw this.result; } } + + public void addAndThrow(T throwable) throws T { + this.add(throwable); + this.throwIfPresent(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index dfdaa4317..d0d69ebc7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -204,4 +204,12 @@ public final class ResourceConfigUtils { } } } + + @SuppressWarnings("unchecked") + public static Map getAsMap(Object obj, String option) { + if (obj instanceof Map map) { + return (Map) map; + } + throw new LocalizedResourceConfigException("warning.config.type.map", String.valueOf(obj), option); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java index 3890ad838..0c003a3eb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java @@ -9,6 +9,7 @@ import java.nio.charset.StandardCharsets; public class VersionHelper { public static final boolean PREMIUM = true; public static final MinecraftVersion MINECRAFT_VERSION; + public static final boolean COMPONENT_RELEASE; private static final int version; private static final int majorVersion; private static final int minorVersion; @@ -71,6 +72,8 @@ public class VersionHelper { majorVersion = major; minorVersion = minor; + COMPONENT_RELEASE = v1_20_5; + mojmap = checkMojMap(); folia = checkFolia(); paper = checkPaper(); diff --git a/gradle.properties b/gradle.properties index 829302ea9..9424ed38f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.8 +project_version=0.0.60.9 config_version=43 -lang_version=22 +lang_version=23 project_group=net.momirealms latest_supported_version=1.21.8 From 0b57d08eca670af962ff7f9cc88cb4e88f2d2fae Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 30 Jul 2025 20:54:33 +0800 Subject: [PATCH 67/83] =?UTF-8?q?=E6=B7=BB=E5=8A=A0attribute-modifiers?= =?UTF-8?q?=E9=9A=8F=E6=9C=BA=E5=8C=96=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../factory/ComponentItemFactory1_20_5.java | 2 +- .../factory/ComponentItemFactory1_21_5.java | 2 +- .../core/item/AbstractItemManager.java | 1 - .../modifier/AttributeModifiersModifier.java | 52 ++++++++++++++----- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 39c72457d..21f37ec25 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -606,6 +606,6 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory implements SimpleNetworkItemDataModif return CONVERTOR.getOrDefault(attributeName, attributeName); } - private final List modifiers; + private final List modifiers; - public AttributeModifiersModifier(List modifiers) { + public AttributeModifiersModifier(List modifiers) { this.modifiers = modifiers; } - public List modifiers() { + public List modifiers() { return this.modifiers; } @@ -103,7 +105,7 @@ public class AttributeModifiersModifier implements SimpleNetworkItemDataModif @Override public Item apply(Item item, ItemBuildContext context) { - return item.attributeModifiers(this.modifiers); + return item.attributeModifiers(this.modifiers.stream().map(it -> it.toAttributeModifier(context)).toList()); } @Override @@ -121,12 +123,40 @@ public class AttributeModifiersModifier implements SimpleNetworkItemDataModif return "AttributeModifiers"; } + public record PreModifier(String type, + AttributeModifier.Slot slot, + Key id, + NumberProvider amount, + AttributeModifier.Operation operation, + AttributeModifiersModifier.PreModifier.@Nullable PreDisplay display) { + + public PreModifier(String type, AttributeModifier.Slot slot, Key id, NumberProvider amount, AttributeModifier.Operation operation, @Nullable PreDisplay display) { + this.amount = amount; + this.type = type; + this.slot = slot; + this.id = id; + this.operation = operation; + this.display = display; + } + + public AttributeModifier toAttributeModifier(ItemBuildContext context) { + return new AttributeModifier(type, slot, id, amount.getDouble(context), operation, display == null ? null : display.toDisplay(context)); + } + + public record PreDisplay(AttributeModifier.Display.Type type, String value) { + + public AttributeModifier.Display toDisplay(ItemBuildContext context) { + return new AttributeModifier.Display(type, AdventureHelper.miniMessage().deserialize(value, context.tagResolvers())); + } + } + } + public static class Factory implements ItemDataModifierFactory { @Override public ItemDataModifier create(Object arg) { MutableInt mutableInt = new MutableInt(0); - List attributeModifiers = ResourceConfigUtils.parseConfigAsList(arg, (map) -> { + List attributeModifiers = ResourceConfigUtils.parseConfigAsList(arg, (map) -> { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.data.attribute_modifiers.missing_type"); Key nativeType = AttributeModifiersModifier.getNativeAttributeName(Key.of(type)); AttributeModifier.Slot slot = AttributeModifier.Slot.valueOf(map.getOrDefault("slot", "any").toString().toUpperCase(Locale.ENGLISH)); @@ -134,24 +164,22 @@ public class AttributeModifiersModifier implements SimpleNetworkItemDataModif mutableInt.add(1); return Key.of("craftengine", "modifier_" + mutableInt.intValue()); }); - double amount = ResourceConfigUtils.getAsDouble( - ResourceConfigUtils.requireNonNullOrThrow(map.get("amount"), "warning.config.item.data.attribute_modifiers.missing_amount"), "amount" - ); + NumberProvider amount = NumberProviders.fromObject(ResourceConfigUtils.requireNonNullOrThrow(map.get("amount"), "warning.config.item.data.attribute_modifiers.missing_amount")); AttributeModifier.Operation operation = AttributeModifier.Operation.valueOf( ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("operation"), "warning.config.item.data.attribute_modifiers.missing_operation").toUpperCase(Locale.ENGLISH) ); - AttributeModifier.Display display = null; + PreModifier.PreDisplay display = null; if (VersionHelper.isOrAbove1_21_6() && map.containsKey("display")) { Map displayMap = MiscUtils.castToMap(map.get("display"), false); AttributeModifier.Display.Type displayType = AttributeModifier.Display.Type.valueOf(ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("type"), "warning.config.item.data.attribute_modifiers.display.missing_type").toUpperCase(Locale.ENGLISH)); if (displayType == AttributeModifier.Display.Type.OVERRIDE) { String miniMessageValue = ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("value"), "warning.config.item.data.attribute_modifiers.display.missing_value"); - display = new AttributeModifier.Display(displayType, AdventureHelper.miniMessage().deserialize(miniMessageValue)); + display = new PreModifier.PreDisplay(displayType, miniMessageValue); } else { - display = new AttributeModifier.Display(displayType, null); + display = new PreModifier.PreDisplay(displayType, null); } } - return new AttributeModifier(nativeType.value(), slot, id, + return new PreModifier(nativeType.value(), slot, id, amount, operation, display); }); return new AttributeModifiersModifier<>(attributeModifiers); From 3e6855aa9e7418b00d2b72bb9de819a6d8ee5f73 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 1 Aug 2025 01:57:36 +0800 Subject: [PATCH 68/83] =?UTF-8?q?=E4=B8=8D=E7=A8=B3=E5=AE=9A=E5=A3=B0?= =?UTF-8?q?=E9=9F=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/sound/BukkitSoundManager.java | 42 ++++++++++++++++--- .../core/sound/AbstractSoundManager.java | 5 +++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java index dce7ca633..099653115 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java @@ -7,11 +7,13 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.sound.AbstractSoundManager; import net.momirealms.craftengine.core.sound.JukeboxSong; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; +import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -26,6 +28,37 @@ public class BukkitSoundManager extends AbstractSoundManager { } } + @Override + protected void registerSounds(Collection sounds) { + if (sounds.isEmpty()) return; + Object registry = MBuiltInRegistries.SOUND_EVENT; + try { + CoreReflections.field$MappedRegistry$frozen.set(registry, false); + for (Key soundEventId : sounds) { + Object resourceLocation = KeyUtils.toResourceLocation(soundEventId); + // 检查之前有没有注册过了 + Object soundEvent = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation); + // 只有没注册才注册,否则会报错 + if (soundEvent == null) { + soundEvent = VersionHelper.isOrAbove1_21_2() ? + CoreReflections.constructor$SoundEvent.newInstance(resourceLocation, Optional.of(0)) : + CoreReflections.constructor$SoundEvent.newInstance(resourceLocation, 0, false); + Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, soundEvent); + CoreReflections.method$Holder$Reference$bindValue.invoke(holder, soundEvent); + CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); + int id = FastNMS.INSTANCE.method$Registry$getId(registry, soundEvent); + super.customSoundsInRegistry.put(id, soundEventId); + } + } + } catch (Exception e) { + this.plugin.logger().warn("Failed to register jukebox songs.", e); + } finally { + try { + CoreReflections.field$MappedRegistry$frozen.set(registry, true); + } catch (ReflectiveOperationException ignored) {} + } + } + @Override protected void registerSongs(Map songs) { if (songs.isEmpty()) return; @@ -40,13 +73,12 @@ public class BukkitSoundManager extends AbstractSoundManager { Object soundId = KeyUtils.toResourceLocation(jukeboxSong.sound()); // 检查之前有没有注册过了 Object song = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation); - - Object soundEvent = VersionHelper.isOrAbove1_21_2() ? - CoreReflections.constructor$SoundEvent.newInstance(soundId, Optional.of(jukeboxSong.range())) : - CoreReflections.constructor$SoundEvent.newInstance(soundId, jukeboxSong.range(), false); - Object soundHolder = CoreReflections.method$Holder$direct.invoke(null, soundEvent); // 只有没注册才注册,否则会报错 if (song == null) { + Object soundEvent = VersionHelper.isOrAbove1_21_2() ? + CoreReflections.constructor$SoundEvent.newInstance(soundId, Optional.of(jukeboxSong.range())) : + CoreReflections.constructor$SoundEvent.newInstance(soundId, jukeboxSong.range(), false); + Object soundHolder = CoreReflections.method$Holder$direct.invoke(null, soundEvent); song = CoreReflections.constructor$JukeboxSong.newInstance(soundHolder, ComponentUtils.adventureToMinecraft(jukeboxSong.description()), jukeboxSong.lengthInSeconds(), jukeboxSong.comparatorOutput()); Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, song); CoreReflections.method$Holder$Reference$bindValue.invoke(holder, song); diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java index eaa7df2ba..a0892da26 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java @@ -19,6 +19,7 @@ public abstract class AbstractSoundManager implements SoundManager { protected final Map songs = new HashMap<>(); protected final SoundParser soundParser; protected final SongParser songParser; + protected final Map customSoundsInRegistry = new HashMap<>(); public AbstractSoundManager(CraftEngine plugin) { this.plugin = plugin; @@ -46,6 +47,8 @@ public abstract class AbstractSoundManager implements SoundManager { @Override public void runDelayedSyncTasks() { if (!VersionHelper.isOrAbove1_21()) return; + // 问题是会踢客户端 + // this.registerSounds(this.byId.keySet()); this.registerSongs(this.songs); } @@ -60,6 +63,8 @@ public abstract class AbstractSoundManager implements SoundManager { protected abstract void registerSongs(Map songs); + protected abstract void registerSounds(Collection sounds); + public class SongParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "jukebox_song", "jukebox-songs", "jukebox-song"}; From 169f0c99731a008b95bce1cfc07db482adac0114 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 1 Aug 2025 04:47:27 +0800 Subject: [PATCH 69/83] =?UTF-8?q?=E6=B3=A8=E5=85=A5=E6=9F=93=E8=89=B2?= =?UTF-8?q?=E9=85=8D=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/factory/BukkitItemFactory.java | 12 -- .../item/recipe/BukkitRecipeManager.java | 153 +++++++------- .../item/recipe/RecipeEventListener.java | 31 +-- .../plugin/injector/RecipeInjector.java | 186 +++++++++++++++++- .../reflection/minecraft/CoreReflections.java | 63 ++++++ .../plugin/reflection/minecraft/MItems.java | 9 + .../bukkit/sound/BukkitSoundManager.java | 1 - .../craftengine/bukkit/util/ItemTags.java | 1 + .../craftengine/core/item/AbstractItem.java | 10 - .../craftengine/core/item/Item.java | 32 ++- .../craftengine/core/item/ItemFactory.java | 4 - .../core/item/recipe/CustomDyeRecipe.java | 159 --------------- gradle.properties | 2 +- 13 files changed, 364 insertions(+), 299 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index e0296b3e2..7b2ded9df 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -13,7 +13,6 @@ import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.StringUtils; import net.momirealms.craftengine.core.util.UniqueKey; @@ -115,18 +114,7 @@ public abstract class BukkitItemFactory> extend return FastNMS.INSTANCE.method$ItemStack$is(literalObject, tag); } - @Override - protected boolean isDyeItem(W item) { - return CoreReflections.clazz$DyeItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject())); - } - @Override - protected Optional dyeColor(W item) { - Object itemStack = item.getLiteralObject(); - Object dyeItem = FastNMS.INSTANCE.method$ItemStack$getItem(itemStack); - if (!CoreReflections.clazz$DyeItem.isInstance(dyeItem)) return Optional.empty(); - return Optional.of(Color.fromDecimal(FastNMS.INSTANCE.method$DyeColor$getTextureDiffuseColor(FastNMS.INSTANCE.method$DyeItem$getDyeColor(dyeItem)))); - } @Override protected void setJavaComponent(W item, Object type, Object value) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 7538a9272..5ae08c405 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -9,6 +9,8 @@ import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.CloneableConstantItem; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.injector.RecipeInjector; +import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; 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.MRegistries; @@ -36,25 +38,70 @@ import java.io.Reader; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.util.*; +import java.util.function.BiConsumer; import java.util.function.Consumer; public class BukkitRecipeManager extends AbstractRecipeManager { private static BukkitRecipeManager instance; + // TODO 需要重构整个 recipe manager + + private static final Object MINECRAFT_RECIPE_MANAGER; + private static final Object MINECRAFT_RECIPE_MAP; + + static { + try { + MINECRAFT_RECIPE_MANAGER = CoreReflections.method$MinecraftServer$getRecipeManager.invoke(CoreReflections.method$MinecraftServer$getServer.invoke(null)); + MINECRAFT_RECIPE_MAP = VersionHelper.isOrAbove1_21_2() ? CoreReflections.field$RecipeManager$recipes.get(MINECRAFT_RECIPE_MANAGER) : null; + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize recipe manager", e); + } + } + + private static final Consumer MINECRAFT_RECIPE_REMOVER = VersionHelper.isOrAbove1_21_2() ? + (id -> { + Object resourceKey = toRecipeResourceKey(id); + FastNMS.INSTANCE.method$RecipeMap$removeRecipe(MINECRAFT_RECIPE_MAP, resourceKey); + }) : + (id -> { + Object resourceLocation = KeyUtils.toResourceLocation(id); + FastNMS.INSTANCE.method$RecipeManager$removeRecipe(MINECRAFT_RECIPE_MANAGER, resourceLocation); + }); + private static final BiConsumer MINECRAFT_RECIPE_ADDER = + VersionHelper.isOrAbove1_21_2() ? + (id, recipe) -> { + Object resourceKey = toRecipeResourceKey(id); + Object recipeHolder = FastNMS.INSTANCE.constructor$RecipeHolder(resourceKey, recipe); + FastNMS.INSTANCE.method$RecipeManager$addRecipe(MINECRAFT_RECIPE_MANAGER, recipeHolder); + } : + VersionHelper.isOrAbove1_20_2() ? + (id, recipe) -> { + Object resourceLocation = KeyUtils.toResourceLocation(id); + Object recipeHolder = FastNMS.INSTANCE.constructor$RecipeHolder(resourceLocation, recipe); + FastNMS.INSTANCE.method$RecipeManager$addRecipe(MINECRAFT_RECIPE_MANAGER, recipeHolder); + } : + (id, recipe) -> { + FastNMS.INSTANCE.method$RecipeManager$addRecipe(MINECRAFT_RECIPE_MANAGER, recipe); + }; + + static { + try { + Key dyeRecipeId = Key.from("armor_dye"); + MINECRAFT_RECIPE_REMOVER.accept(dyeRecipeId); + MINECRAFT_RECIPE_ADDER.accept(dyeRecipeId, RecipeInjector.createCustomDyeRecipe()); + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to inject dye recipes", e); + } + } + + private static final List injectedIngredients = new ArrayList<>(); // 将自定义配方转为“广义”配方,接受更加宽容的输入 // 部分过程借助bukkit完成,部分直接通过nms方法注册 private static final Map>> MIXED_RECIPE_CONVERTORS = new HashMap<>(); - private static final List injectedIngredients = new ArrayList<>(); - private static final IdentityHashMap, Object> CE_RECIPE_2_NMS_HOLDER = new IdentityHashMap<>(); - public static final CustomDyeRecipe DYE_RECIPE = new CustomDyeRecipe<>(); - private static Object nmsRecipeManager; + private static final IdentityHashMap, Object> MINECRAFT_RECIPE_HOLDER_BY_RECIPE = new IdentityHashMap<>(); - private static void registerNMSSmithingRecipe(Object recipe) { - try { - CoreReflections.method$RecipeManager$addRecipe.invoke(nmsRecipeManager(), recipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register smithing recipe", e); - } + public static Object toRecipeResourceKey(Key id) { + return FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(id)); } private static void registerBukkitShapedRecipe(Object recipe) { @@ -124,17 +171,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRANSFORM, (BukkitRecipeConvertor>) (id, recipe) -> { try { Object nmsRecipe = createMinecraftSmithingTransformRecipe(recipe); - if (VersionHelper.isOrAbove1_21_2()) { - nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance( - CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe); - } else if (VersionHelper.isOrAbove1_20_2()) { - nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(KeyUtils.toResourceLocation(id), nmsRecipe); - } else { - Object finalNmsRecipe0 = nmsRecipe; - return () -> registerNMSSmithingRecipe(finalNmsRecipe0); - } - Object finalNmsRecipe = nmsRecipe; - return () -> registerNMSSmithingRecipe(finalNmsRecipe); + return () -> MINECRAFT_RECIPE_ADDER.accept(id, nmsRecipe); } catch (InvalidRecipeIngredientException e) { throw e; } catch (Exception e) { @@ -145,17 +182,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRIM, (BukkitRecipeConvertor>) (id, recipe) -> { try { Object nmsRecipe = createMinecraftSmithingTrimRecipe(recipe); - if (VersionHelper.isOrAbove1_21_2()) { - nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance( - CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe); - } else if (VersionHelper.isOrAbove1_20_2()) { - nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(KeyUtils.toResourceLocation(id), nmsRecipe); - } else { - Object finalNmsRecipe0 = nmsRecipe; - return () -> registerNMSSmithingRecipe(finalNmsRecipe0); - } - Object finalNmsRecipe = nmsRecipe; - return () -> registerNMSSmithingRecipe(finalNmsRecipe); + return () -> MINECRAFT_RECIPE_ADDER.accept(id, nmsRecipe); } catch (InvalidRecipeIngredientException e) { throw e; } catch (Exception e) { @@ -281,20 +308,15 @@ public class BukkitRecipeManager extends AbstractRecipeManager { this.plugin = plugin; this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager()); this.crafterEventListener = VersionHelper.isOrAbove1_21() ? new CrafterEventListener(plugin, this, plugin.itemManager()) : null; - try { - nmsRecipeManager = CoreReflections.method$MinecraftServer$getRecipeManager.invoke(CoreReflections.method$MinecraftServer$getServer.invoke(null)); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to get minecraft recipe manager", e); - } } public Object nmsRecipeHolderByRecipe(Recipe recipe) { if (super.isReloading) return null; - return CE_RECIPE_2_NMS_HOLDER.get(recipe); + return MINECRAFT_RECIPE_HOLDER_BY_RECIPE.get(recipe); } - public static Object nmsRecipeManager() { - return nmsRecipeManager; + public static Object minecraftRecipeManager() { + return MINECRAFT_RECIPE_MANAGER; } public static BukkitRecipeManager instance() { @@ -315,8 +337,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager { super.isReloading = true; if (VersionHelper.isOrAbove1_21_2()) { try { - this.stolenFeatureFlagSet = CoreReflections.field$RecipeManager$featureflagset.get(nmsRecipeManager); - CoreReflections.field$RecipeManager$featureflagset.set(nmsRecipeManager, null); + this.stolenFeatureFlagSet = CoreReflections.field$RecipeManager$featureflagset.get(MINECRAFT_RECIPE_MANAGER); + CoreReflections.field$RecipeManager$featureflagset.set(MINECRAFT_RECIPE_MANAGER, null); } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to steal featureflagset", e); } @@ -347,7 +369,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void disable() { unload(); - CE_RECIPE_2_NMS_HOLDER.clear(); + MINECRAFT_RECIPE_HOLDER_BY_RECIPE.clear(); // 不是服务器关闭造成disable,那么需要把配方卸载干净 if (!Bukkit.isStopping()) { for (Runnable task : this.delayedTasksOnMainThread) { @@ -365,7 +387,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (isBrewingRecipe) { Bukkit.getPotionBrewer().removePotionMix(new NamespacedKey(key.namespace(), key.value())); } else { - unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value())); + MINECRAFT_RECIPE_REMOVER.accept(key); } } @@ -406,19 +428,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { return (BukkitRecipeConvertor) MIXED_RECIPE_CONVERTORS.get(recipe.type()); } - private void unregisterNMSRecipe(NamespacedKey key) { - try { - if (VersionHelper.isOrAbove1_21_2()) { - Object recipeMap = CoreReflections.field$RecipeManager$recipes.get(nmsRecipeManager); - CoreReflections.method$RecipeMap$removeRecipe.invoke(recipeMap, CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, key)); - } else { - Bukkit.removeRecipe(key); - } - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to unregister nms recipes", e); - } - } - @SuppressWarnings("unchecked") private void injectDataPackRecipes() { try { @@ -501,6 +510,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void runDelayedSyncTasks() { if (!Config.enableRecipeSystem()) return; + try { // run delayed tasks for (Runnable r : this.delayedTasksOnMainThread) { @@ -510,13 +520,13 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // give flags back on 1.21.2+ if (VersionHelper.isOrAbove1_21_2() && this.stolenFeatureFlagSet != null) { - CoreReflections.field$RecipeManager$featureflagset.set(nmsRecipeManager(), this.stolenFeatureFlagSet); + CoreReflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager(), this.stolenFeatureFlagSet); this.stolenFeatureFlagSet = null; } // refresh recipes if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager()); + CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager()); } // send to players @@ -536,13 +546,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // clear cache injectedIngredients.clear(); - CE_RECIPE_2_NMS_HOLDER.clear(); + MINECRAFT_RECIPE_HOLDER_BY_RECIPE.clear(); // create mappings for (Map.Entry> entry : this.byId.entrySet()) { Optional nmsRecipe = getOptionalNMSRecipe(entry.getKey()); - nmsRecipe.ifPresent(o -> CE_RECIPE_2_NMS_HOLDER.put(entry.getValue(), o)); + nmsRecipe.ifPresent(o -> MINECRAFT_RECIPE_HOLDER_BY_RECIPE.put(entry.getValue(), o)); } - CE_RECIPE_2_NMS_HOLDER.put(DYE_RECIPE, getOptionalNMSRecipe(CustomDyeRecipe.ID).orElseThrow(() -> new IllegalStateException("DyeRecipe not found"))); super.isReloading = false; } catch (Exception e) { this.plugin.logger().warn("Failed to run delayed recipe tasks", e); @@ -568,7 +577,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } private void handleDataPackShapelessRecipe(Key id, VanillaShapelessRecipe recipe, Consumer callback) { - NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createDataPackResultStack(recipe.result()); boolean hasCustomItemInTag = false; List> ingredientList = new ArrayList<>(); @@ -596,7 +604,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (hasCustomItemInTag) { Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - unregisterNMSRecipe(key); + MINECRAFT_RECIPE_REMOVER.accept(id); converted.run(); }); } @@ -604,7 +612,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } private void handleDataPackShapedRecipe(Key id, VanillaShapedRecipe recipe, Consumer callback) { - NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createDataPackResultStack(recipe.result()); boolean hasCustomItemInTag = false; Map> ingredients = new HashMap<>(); @@ -633,7 +640,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (hasCustomItemInTag) { Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - unregisterNMSRecipe(key); + MINECRAFT_RECIPE_REMOVER.accept(id); converted.run(); }); } @@ -644,7 +651,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { VanillaCookingRecipe recipe, HeptaFunction, Integer, Float, CustomRecipeResult, CustomCookingRecipe> constructor2, Consumer callback) { - NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createDataPackResultStack(recipe.result()); Set holders = new HashSet<>(); boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), holders::add); @@ -657,7 +663,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (hasCustomItemInTag) { Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - unregisterNMSRecipe(key); + MINECRAFT_RECIPE_REMOVER.accept(id); converted.run(); }); } @@ -665,7 +671,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } private void handleDataPackSmithingTransform(Key id, VanillaSmithingTransformRecipe recipe, Consumer callback) { - NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createDataPackResultStack(recipe.result()); boolean hasCustomItemInTag; @@ -689,7 +694,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (hasCustomItemInTag) { Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - unregisterNMSRecipe(key); + MINECRAFT_RECIPE_REMOVER.accept(id); converted.run(); }); } @@ -697,8 +702,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } private void handleDataPackSmithingTrim(Key id, VanillaSmithingTrimRecipe recipe, Consumer callback) { - NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); - boolean hasCustomItemInTag; Set additionHolders = new HashSet<>(); hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add); @@ -718,7 +721,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (hasCustomItemInTag) { Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - unregisterNMSRecipe(key); + MINECRAFT_RECIPE_REMOVER.accept(id); converted.run(); }); } @@ -883,12 +886,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (VersionHelper.isOrAbove1_21_2()) { Object resourceKey = FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(id)); @SuppressWarnings("unchecked") - Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceKey); + Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(MINECRAFT_RECIPE_MANAGER, resourceKey); return optional; } else { Object resourceLocation = KeyUtils.toResourceLocation(id); @SuppressWarnings("unchecked") - Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceLocation); + Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(MINECRAFT_RECIPE_MANAGER, resourceLocation); return optional; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 4f5d13d3f..79e9a28f8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -342,7 +342,7 @@ public class RecipeEventListener implements Listener { try { @SuppressWarnings("unchecked") Optional optionalMCRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor( - BukkitRecipeManager.nmsRecipeManager(), + BukkitRecipeManager.minecraftRecipeManager(), MRecipeTypes.CAMPFIRE_COOKING, CoreReflections.constructor$SingleRecipeInput.newInstance(FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(event.getPlayer().getWorld()), @@ -699,7 +699,11 @@ public class RecipeEventListener implements Listener { } try { + // TODO 全部改注入 Object mcRecipe = CraftBukkitReflections.field$CraftComplexRecipe$recipe.get(complexRecipe); + if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) { + return; + } // Repair recipe if (CoreReflections.clazz$RepairItemRecipe.isInstance(mcRecipe)) { @@ -745,8 +749,6 @@ public class RecipeEventListener implements Listener { int newItemDamage = Math.max(0, newItem.maxDamage() - remainingDurability); newItem.damage(newItemDamage); inventory.setResult(newItem.getItem()); - } else if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) { - handlePossibleDyeRecipe(event, false); } else if (CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) { ItemStack[] itemStacks = inventory.getMatrix(); for (ItemStack itemStack : itemStacks) { @@ -826,29 +828,6 @@ public class RecipeEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true) - public void onDyeRecipe(PrepareItemCraftEvent event) { - org.bukkit.inventory.Recipe recipe = event.getRecipe(); - if (recipe != null) { - return; - } - handlePossibleDyeRecipe(event, true); - } - - private void handlePossibleDyeRecipe(PrepareItemCraftEvent event, boolean correct) { - // dye recipe - CraftingInventory inventory = event.getInventory(); - CraftingInput input = getCraftingInput(inventory); - if (input == null) return; - if (BukkitRecipeManager.DYE_RECIPE.matches(input)) { - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - event.getInventory().setResult(BukkitRecipeManager.DYE_RECIPE.assemble(input, ItemBuildContext.of(this.plugin.adapt(player)))); - if (correct) { - correctCraftingRecipeUsed(inventory, BukkitRecipeManager.DYE_RECIPE); - } - } - } - @EventHandler(ignoreCancelled = true) public void onCraftingRecipe(PrepareItemCraftEvent event) { if (!Config.enableRecipeSystem()) return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 7a8016ace..3298c5eba 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -17,22 +17,30 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRecipeTypes; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ReflectionUtils; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.*; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; public class RecipeInjector { private static Class clazz$InjectedCacheChecker; - + private static Class clazz$InjectedArmorDyeRecipe; + public static void init() { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); clazz$InjectedCacheChecker = byteBuddy @@ -70,6 +78,35 @@ public class RecipeInjector { .make() .load(RecipeInjector.class.getClassLoader()) .getLoaded(); + clazz$InjectedArmorDyeRecipe = byteBuddy + .subclass(CoreReflections.clazz$ArmorDyeRecipe, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) + .name("net.momirealms.craftengine.bukkit.item.recipe.ArmorDyeRecipe") + .method((VersionHelper.isOrAbove1_21() ? + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$Level) : + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$Level) + ).and(ElementMatchers.returns(boolean.class))) + .intercept(MethodDelegation.to(MatchesInterceptor.INSTANCE)) + .method(( + VersionHelper.isOrAbove1_21() ? + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$HolderLookup$Provider) : + VersionHelper.isOrAbove1_20_5() ? + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$HolderLookup$Provider) : + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$RegistryAccess) + ).and(ElementMatchers.returns(CoreReflections.clazz$ItemStack))) + .intercept(MethodDelegation.to(AssembleInterceptor.INSTANCE)) + .make() + .load(RecipeInjector.class.getClassLoader()) + .getLoaded(); + } + + public static Object createCustomDyeRecipe() throws ReflectiveOperationException { + if (VersionHelper.isOrAbove1_20_2()) { + Constructor constructor = ReflectionUtils.getConstructor(clazz$InjectedArmorDyeRecipe, CoreReflections.clazz$CraftingBookCategory); + return constructor.newInstance(CoreReflections.instance$CraftingBookCategory$MISC); + } else { + Constructor constructor = ReflectionUtils.getConstructor(clazz$InjectedArmorDyeRecipe, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$CraftingBookCategory); + return constructor.newInstance(KeyUtils.toResourceLocation(Key.of("armor_dye")), CoreReflections.instance$CraftingBookCategory$MISC); + } } public static void injectCookingBlockEntity(Object entity) throws ReflectiveOperationException { @@ -101,6 +138,139 @@ public class RecipeInjector { } } + private static final Function INGREDIENT_COUNT_CHECKER = + VersionHelper.isOrAbove1_21() ? + (input) -> FastNMS.INSTANCE.method$CraftingInput$ingredientCount(input) < 2 : + (container) -> false; + private static final Function INGREDIENT_COUNT_GETTER = + VersionHelper.isOrAbove1_21() ? + FastNMS.INSTANCE::method$CraftingInput$ingredientCount : + FastNMS.INSTANCE::method$Container$getContainerSize; + private static final BiFunction INGREDIENT_GETTER = + VersionHelper.isOrAbove1_21() ? + FastNMS.INSTANCE::method$CraftingInput$getItem : + FastNMS.INSTANCE::method$Container$getItem; + + public static class MatchesInterceptor { + public static final MatchesInterceptor INSTANCE = new MatchesInterceptor(); + + @RuntimeType + public Object intercept(@AllArguments Object[] args) { + Object input = args[0]; + if (INGREDIENT_COUNT_CHECKER.apply(input)) { + return false; + } + int size = INGREDIENT_COUNT_GETTER.apply(input); + Item itemToDye = null; + boolean hasDye = false; + for (int i = 0; i < size; i++) { + Object itemStack = INGREDIENT_GETTER.apply(input, i); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) { + continue; + } + Item wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)); + if (isDyeable(wrapped)) { + if (itemToDye != null) { + return false; + } + itemToDye = wrapped; + } else { + if (!isDye(wrapped)) { + return false; + } + hasDye = true; + } + } + return hasDye && itemToDye != null; + } + } + + public static class AssembleInterceptor { + public static final AssembleInterceptor INSTANCE = new AssembleInterceptor(); + + @RuntimeType + public Object intercept(@AllArguments Object[] args) { + List colors = new ArrayList<>(); + Item itemToDye = null; + Object input = args[0]; + int size = INGREDIENT_COUNT_GETTER.apply(input); + for (int i = 0; i < size; i++) { + Object itemStack = INGREDIENT_GETTER.apply(input, i); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) { + continue; + } + Item wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)); + if (isDyeable(wrapped)) { + itemToDye = wrapped.copyWithCount(1); + } else { + Color dyeColor = getDyeColor(wrapped); + if (dyeColor != null) { + colors.add(dyeColor); + } else { + return CoreReflections.instance$ItemStack$EMPTY; + } + } + } + if (itemToDye == null || itemToDye.isEmpty() || colors.isEmpty()) { + return null; + } + return itemToDye.applyDyedColors(colors).getLiteralObject(); + } + } + + @Nullable + private static Color getDyeColor(final Item dyeItem) { + Optional> optionalCustomItem = dyeItem.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + return Optional.ofNullable(customItem.settings().dyeColor()).orElseGet(() -> getVanillaDyeColor(dyeItem)); + } + return getVanillaDyeColor(dyeItem); + } + + private static final Predicate> IS_DYEABLE = + VersionHelper.isOrAbove1_20_5() ? + (item -> item.is(ItemTags.DYEABLE)) : + (item -> { + Object itemLike = FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()); + return CoreReflections.clazz$DyeableLeatherItem.isInstance(itemLike); + }); + + private static boolean isDyeable(final Item item) { + Optional> optionalCustomItem = item.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + if (customItem.settings().dyeable() == Tristate.FALSE) { + return false; + } + if (customItem.settings().dyeable() == Tristate.TRUE) { + return true; + } + } + return IS_DYEABLE.test(item); + } + + @Nullable + private static Color getVanillaDyeColor(final Item item) { + Object itemStack = item.getLiteralObject(); + Object dyeItem = FastNMS.INSTANCE.method$ItemStack$getItem(itemStack); + if (!CoreReflections.clazz$DyeItem.isInstance(dyeItem)) return null; + return Color.fromDecimal(FastNMS.INSTANCE.method$DyeColor$getTextureDiffuseColor(FastNMS.INSTANCE.method$DyeItem$getDyeColor(dyeItem))); + } + + private static boolean isDye(Item dyeItem) { + Optional> optionalCustomItem = dyeItem.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + return customItem.settings().dyeColor() != null || isVanillaDyeItem(dyeItem); + } + return isVanillaDyeItem(dyeItem); + } + + private static boolean isVanillaDyeItem(Item item) { + return CoreReflections.clazz$DyeItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject())); + } + @SuppressWarnings("DuplicatedCode") public static class GetRecipeForMethodInterceptor1_20 { public static final GetRecipeForMethodInterceptor1_20 INSTANCE = new GetRecipeForMethodInterceptor1_20(); @@ -110,7 +280,7 @@ public class RecipeInjector { public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); - Optional> optionalRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); + Optional> optionalRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); if (optionalRecipe.isEmpty()) { return Optional.empty(); } @@ -156,7 +326,7 @@ public class RecipeInjector { public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); + Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); if (optionalRecipe.isEmpty()) { return Optional.empty(); } @@ -202,7 +372,7 @@ public class RecipeInjector { public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); + Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); if (optionalRecipe.isEmpty()) { return Optional.empty(); } @@ -243,7 +413,7 @@ public class RecipeInjector { public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object lastRecipeResourceKey = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceKey); + Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceKey); if (optionalRecipe.isEmpty()) { return Optional.empty(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 76514f5de..125a9a8cf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3903,4 +3903,67 @@ public final class CoreReflections { "world.item.DyeItem" ) ); + + public static final Method method$Recipe$matches = requireNonNull( + VersionHelper.isOrAbove1_21() ? + ReflectionUtils.getMethod(clazz$Recipe, boolean.class, clazz$RecipeInput, clazz$Level) : + ReflectionUtils.getMethod(clazz$Recipe, boolean.class, clazz$Container, clazz$Level) + ); + + public static final Method method$Recipe$assemble = requireNonNull( + VersionHelper.isOrAbove1_21() ? + ReflectionUtils.getMethod(clazz$Recipe, clazz$ItemStack, clazz$RecipeInput, clazz$HolderLookup$Provider) : + VersionHelper.isOrAbove1_20_5() ? + ReflectionUtils.getMethod(clazz$Recipe, clazz$ItemStack, clazz$Container, clazz$HolderLookup$Provider) : + ReflectionUtils.getMethod(clazz$Recipe, clazz$ItemStack, clazz$Container, clazz$RegistryAccess) + ); + + public static final Class clazz$CraftingBookCategory = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.crafting.CraftingBookCategory", + "world.item.crafting.CraftingBookCategory" + ) + ); + + public static final Method method$CraftingBookCategory$values = requireNonNull( + ReflectionUtils.getStaticMethod(clazz$CraftingBookCategory, clazz$CraftingBookCategory.arrayType()) + ); + + public static final Object instance$CraftingBookCategory$BUILDING; + public static final Object instance$CraftingBookCategory$REDSTONE; + public static final Object instance$CraftingBookCategory$EQUIPMENT; + public static final Object instance$CraftingBookCategory$MISC; + + static { + try { + Object[] values = (Object[]) method$CraftingBookCategory$values.invoke(null); + instance$CraftingBookCategory$BUILDING = values[0]; + instance$CraftingBookCategory$REDSTONE = values[1]; + instance$CraftingBookCategory$EQUIPMENT = values[2]; + instance$CraftingBookCategory$MISC = values[3]; + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize CraftingBookCategory", e); + } + } + + public static final Class clazz$CraftingInput = MiscUtils.requireNonNullIf( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.crafting.CraftingInput", + "world.item.crafting.CraftingInput" + ), VersionHelper.isOrAbove1_21() + ); + + public static final Class clazz$CraftingContainer = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.inventory.InventoryCrafting", + "world.inventory.CraftingContainer" + ) + ); + + public static final Class clazz$DyeableLeatherItem = MiscUtils.requireNonNullIf( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.IDyeable", + "world.item.DyeableLeatherItem" + ), !VersionHelper.isOrAbove1_20_5() + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java index cfe080d81..258666205 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java @@ -1,6 +1,9 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; public final class MItems { private MItems() {} @@ -9,11 +12,17 @@ public final class MItems { public static final Object WATER_BUCKET; public static final Object BARRIER; + @Nullable private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, rl); } + @Nullable + public static Object getById(Key id) { + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(id)); + } + static { AIR = getById("air"); WATER_BUCKET = getById("water_bucket"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java index 099653115..a2981f6be 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java @@ -7,7 +7,6 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.sound.AbstractSoundManager; import net.momirealms.craftengine.core.sound.JukeboxSong; import net.momirealms.craftengine.core.util.Key; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java index 1f35e3e90..e94bc4a32 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java @@ -12,6 +12,7 @@ public class ItemTags { public static final Key AXES = Key.of("minecraft:axes"); public static final Key SWORDS = Key.of("minecraft:swords"); + public static final Key DYEABLE = Key.of("minecraft:dyeable"); private ItemTags() {} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 872aa411d..af97388f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -481,14 +481,4 @@ public class AbstractItem, I> implements Item { public void shrink(int amount) { this.item.shrink(amount); } - - @Override - public boolean isDyeItem() { - return this.factory.isDyeItem(this.item); - } - - @Override - public Optional dyeColor() { - return this.factory.dyeColor(this.item); - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index ee799b262..30c17b8b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -214,7 +214,33 @@ public interface Item { byte[] toByteArray(); - boolean isDyeItem(); - - Optional dyeColor(); + default Item applyDyedColors(List colors) { + int totalRed = 0; + int totalGreen = 0; + int totalBlue = 0; + int totalMaxComponent = 0; + int colorCount = 0; + Optional existingColor = dyedColor(); + existingColor.ifPresent(colors::add); + for (Color color : colors) { + int dyeRed = color.r(); + int dyeGreen = color.g(); + int dyeBlue = color.b(); + totalMaxComponent += Math.max(dyeRed, Math.max(dyeGreen, dyeBlue)); + totalRed += dyeRed; + totalGreen += dyeGreen; + totalBlue += dyeBlue; + ++colorCount; + } + int avgRed = totalRed / colorCount; + int avgGreen = totalGreen / colorCount; + int avgBlue = totalBlue / colorCount; + float avgMaxComponent = (float) totalMaxComponent / (float)colorCount; + float currentMaxComponent = (float) Math.max(avgRed, Math.max(avgGreen, avgBlue)); + avgRed = (int) ((float) avgRed * avgMaxComponent / currentMaxComponent); + avgGreen = (int) ((float) avgGreen * avgMaxComponent / currentMaxComponent); + avgBlue = (int) ((float) avgBlue * avgMaxComponent / currentMaxComponent); + Color finalColor = new Color(0, avgRed, avgGreen, avgBlue); + return dyedColor(finalColor); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index f88830935..1391a199d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -213,9 +213,5 @@ public abstract class ItemFactory, I> { protected abstract UniqueKey recipeIngredientID(W item); - protected abstract boolean isDyeItem(W item); - - protected abstract Optional dyeColor(W item); - protected abstract void attributeModifiers(W item, List modifiers); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java deleted file mode 100644 index 0e0201af5..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomDyeRecipe.java +++ /dev/null @@ -1,159 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe; - -import net.momirealms.craftengine.core.item.CustomItem; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; -import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; -import net.momirealms.craftengine.core.util.Color; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.Tristate; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -public class CustomDyeRecipe implements Recipe { - public static final Key ID = Key.of("armor_dye"); - private static final Key DYEABLE = Key.of("dyeable"); - - public CustomDyeRecipe() { - } - - @SuppressWarnings("unchecked") - @Override - public T assemble(RecipeInput input, ItemBuildContext context) { - List colors = new ArrayList<>(); - CraftingInput craftingInput = (CraftingInput) input; - Item itemToDye = null; - for (UniqueIdItem uniqueIdItem : craftingInput) { - if (uniqueIdItem.isEmpty()) { - continue; - } - if (isDyeable(uniqueIdItem)) { - itemToDye = uniqueIdItem.item().copyWithCount(1); - } else { - Color dyeColor = getDyeColor(uniqueIdItem); - if (dyeColor != null) { - colors.add(dyeColor); - } else { - return null; - } - } - } - if (itemToDye == null || itemToDye.isEmpty() || colors.isEmpty()) { - return null; - } - return applyDyes(itemToDye, colors).getItem(); - } - - private Item applyDyes(Item item, List colors) { - int totalRed = 0; - int totalGreen = 0; - int totalBlue = 0; - int totalMaxComponent = 0; - int colorCount = 0; - Optional existingColor = item.dyedColor(); - existingColor.ifPresent(colors::add); - for (Color color : colors) { - int dyeRed = color.r(); - int dyeGreen = color.g(); - int dyeBlue = color.b(); - totalMaxComponent += Math.max(dyeRed, Math.max(dyeGreen, dyeBlue)); - totalRed += dyeRed; - totalGreen += dyeGreen; - totalBlue += dyeBlue; - ++colorCount; - } - int avgRed = totalRed / colorCount; - int avgGreen = totalGreen / colorCount; - int avgBlue = totalBlue / colorCount; - float avgMaxComponent = (float) totalMaxComponent / (float)colorCount; - float currentMaxComponent = (float) Math.max(avgRed, Math.max(avgGreen, avgBlue)); - avgRed = (int) ((float) avgRed * avgMaxComponent / currentMaxComponent); - avgGreen = (int) ((float) avgGreen * avgMaxComponent / currentMaxComponent); - avgBlue = (int) ((float) avgBlue * avgMaxComponent / currentMaxComponent); - Color finalColor = new Color(0, avgRed, avgGreen, avgBlue); - return item.dyedColor(finalColor); - } - - @SuppressWarnings("unchecked") - @Override - public boolean matches(RecipeInput input) { - CraftingInput craftingInput = (CraftingInput) input; - if (craftingInput.ingredientCount() < 2) { - return false; - } - boolean hasItemToDye = false; - boolean hasDye = false; - for(int i = 0; i < craftingInput.size(); ++i) { - UniqueIdItem item = craftingInput.getItem(i); - if (!item.isEmpty()) { - if (isDyeable(item)) { - if (hasItemToDye) { - return false; - } - hasItemToDye = true; - } else { - if (!isDye(item)) { - return false; - } - hasDye = true; - } - } - } - return hasDye && hasItemToDye; - } - - private boolean isDyeable(final UniqueIdItem item) { - Optional> optionalCustomItem = item.item().getCustomItem(); - if (optionalCustomItem.isPresent()) { - CustomItem customItem = optionalCustomItem.get(); - if (customItem.settings().dyeable() == Tristate.FALSE) { - return false; - } - if (customItem.settings().dyeable() == Tristate.TRUE) { - return true; - } - } - return item.item().is(DYEABLE); - } - - private boolean isDye(final UniqueIdItem item) { - Item dyeItem = item.item(); - Optional> optionalCustomItem = item.item().getCustomItem(); - if (optionalCustomItem.isPresent()) { - CustomItem customItem = optionalCustomItem.get(); - return customItem.settings().dyeColor() != null || dyeItem.isDyeItem(); - } - return dyeItem.isDyeItem(); - } - - @Nullable - private Color getDyeColor(final UniqueIdItem item) { - Item dyeItem = item.item(); - Optional> optionalCustomItem = item.item().getCustomItem(); - if (optionalCustomItem.isPresent()) { - CustomItem customItem = optionalCustomItem.get(); - return Optional.ofNullable(customItem.settings().dyeColor()).orElseGet(() -> dyeItem.dyeColor().orElse(null)); - } - return dyeItem.dyeColor().orElse(null); - } - - @Override - public List> ingredientsInUse() { - return List.of(); - } - - @Override - public @NotNull Key type() { - return RecipeTypes.SPECIAL; - } - - @Override - public Key id() { - return ID; - } -} diff --git a/gradle.properties b/gradle.properties index 9424ed38f..1d95c9947 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.18 -nms_helper_version=1.0.43 +nms_helper_version=1.0.46 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From f1da4dc4a1fcc7ad4ca2cbc793f3bf813d464361 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 2 Aug 2025 00:41:55 +0800 Subject: [PATCH 70/83] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=89=B9=E6=AE=8A?= =?UTF-8?q?=E9=85=8D=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/listener/ItemEventListener.java | 2 +- .../item/recipe/BukkitRecipeManager.java | 10 +- .../item/recipe/RecipeEventListener.java | 96 ++---- .../plugin/injector/RecipeInjector.java | 289 +++++++++++++++--- .../craftengine/core/item/ItemKeys.java | 1 + .../craftengine/core/item/ItemSettings.java | 30 +- .../core/item/data/FireworkExplosion.java | 6 + gradle.properties | 4 +- 8 files changed, 317 insertions(+), 121 deletions(-) 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 2b2277636..ab5660c90 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 @@ -468,7 +468,7 @@ public class ItemEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onEntityDamage(EntityDamageEvent event) { if (event.getEntity() instanceof org.bukkit.entity.Item item) { - Optional.ofNullable(this.plugin.itemManager().wrap(item.getItemStack())) + Optional.of(this.plugin.itemManager().wrap(item.getItemStack())) .flatMap(Item::getCustomItem) .ifPresent(it -> { if (it.settings().invulnerable().contains(DamageCauseUtils.fromBukkit(event.getCause()))) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 5ae08c405..0b018c5aa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -88,9 +88,15 @@ public class BukkitRecipeManager extends AbstractRecipeManager { try { Key dyeRecipeId = Key.from("armor_dye"); MINECRAFT_RECIPE_REMOVER.accept(dyeRecipeId); - MINECRAFT_RECIPE_ADDER.accept(dyeRecipeId, RecipeInjector.createCustomDyeRecipe()); + MINECRAFT_RECIPE_ADDER.accept(dyeRecipeId, RecipeInjector.createCustomDyeRecipe(dyeRecipeId)); + Key repairRecipeId = Key.from("repair_item"); + MINECRAFT_RECIPE_REMOVER.accept(repairRecipeId); + MINECRAFT_RECIPE_ADDER.accept(repairRecipeId, RecipeInjector.createRepairItemRecipe(repairRecipeId)); + Key fireworkStarFadeRecipeId = Key.from("firework_star_fade"); + MINECRAFT_RECIPE_REMOVER.accept(fireworkStarFadeRecipeId); + MINECRAFT_RECIPE_ADDER.accept(fireworkStarFadeRecipeId, RecipeInjector.createFireworkStarFadeRecipe(fireworkStarFadeRecipeId)); } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to inject dye recipes", e); + throw new ReflectionInitException("Failed to inject special recipes", e); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 79e9a28f8..2eb25c028 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -481,7 +481,7 @@ public class RecipeEventListener implements Listener { // 如果禁止在铁砧使用两个相同物品修复 firstCustom.ifPresent(it -> { - if (!it.settings().canRepair()) { + if (it.settings().canRepair() == Tristate.FALSE) { event.setResult(null); } }); @@ -522,7 +522,7 @@ public class RecipeEventListener implements Listener { Key firstId = wrappedFirst.id(); Optional> optionalCustomTool = wrappedFirst.getCustomItem(); // 物品无法被修复 - if (optionalCustomTool.isPresent() && !optionalCustomTool.get().settings().canRepair()) { + if (optionalCustomTool.isPresent() && optionalCustomTool.get().settings().canRepair() == Tristate.FALSE) { return; } @@ -679,93 +679,52 @@ public class RecipeEventListener implements Listener { } // only handle repair items for the moment - @EventHandler(ignoreCancelled = true) + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onSpecialRecipe(PrepareItemCraftEvent event) { -// if (!ConfigManager.enableRecipeSystem()) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); - if (recipe == null) - return; if (!(recipe instanceof ComplexRecipe complexRecipe)) return; CraftingInventory inventory = event.getInventory(); + ItemStack result = inventory.getResult(); + if (ItemStackUtils.isEmpty(result)) + return; boolean hasCustomItem = ItemStackUtils.hasCustomItem(inventory.getMatrix()); - if (!hasCustomItem) { + if (!hasCustomItem) return; - } - if (!CraftBukkitReflections.clazz$CraftComplexRecipe.isInstance(complexRecipe)) { - inventory.setResult(null); return; } - try { - // TODO 全部改注入 Object mcRecipe = CraftBukkitReflections.field$CraftComplexRecipe$recipe.get(complexRecipe); - if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) { + if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe) || CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) { return; } - - // Repair recipe + // 处理修复配方,在此处理才能使用玩家参数构建物品 if (CoreReflections.clazz$RepairItemRecipe.isInstance(mcRecipe)) { - // repair item - ItemStack[] itemStacks = inventory.getMatrix(); - Pair onlyTwoItems = getTheOnlyTwoItem(itemStacks); - if (onlyTwoItems.left() == null || onlyTwoItems.right() == null) { - inventory.setResult(null); - return; - } - - Item left = plugin.itemManager().wrap(onlyTwoItems.left()); - Item right = plugin.itemManager().wrap(onlyTwoItems.right()); - if (!left.id().equals(right.id())) { - inventory.setResult(null); - return; - } - - int totalDamage = right.damage().orElse(0) + left.damage().orElse(0); - int totalMaxDamage = left.maxDamage() + right.maxDamage(); - // should be impossible, but take care - if (totalDamage >= totalMaxDamage) { - inventory.setResult(null); - return; - } - - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - - Optional> customItemOptional = plugin.itemManager().getCustomItem(left.id()); + Pair theOnlyTwoItem = getTheOnlyTwoItem(inventory.getMatrix()); + if (theOnlyTwoItem == null) return; + Item first = BukkitItemManager.instance().wrap(theOnlyTwoItem.left()); + Item right = BukkitItemManager.instance().wrap(theOnlyTwoItem.right()); + int max = Math.max(first.maxDamage(), right.maxDamage()); + int durability1 = first.maxDamage() - first.damage().orElse(0); + int durability2 = right.maxDamage() - right.damage().orElse(0); + int finalDurability = durability1 + durability2 + max * 5 / 100; + Optional> customItemOptional = plugin.itemManager().getCustomItem(first.id()); if (customItemOptional.isEmpty()) { inventory.setResult(null); return; } - - CustomItem customItem = customItemOptional.get(); - if (!customItem.settings().canRepair()) { - inventory.setResult(null); - return; - } - - Item newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player))); - int remainingDurability = totalMaxDamage - totalDamage; - int newItemDamage = Math.max(0, newItem.maxDamage() - remainingDurability); - newItem.damage(newItemDamage); + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); + Item newItem = customItemOptional.get().buildItem(plugin.adapt(player)); + newItem.maxDamage(max); + newItem.damage(Math.max(max - finalDurability, 0)); inventory.setResult(newItem.getItem()); - } else if (CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) { - ItemStack[] itemStacks = inventory.getMatrix(); - for (ItemStack itemStack : itemStacks) { - if (itemStack == null) continue; - Item item = plugin.itemManager().wrap(itemStack); - Optional> optionalCustomItem = item.getCustomItem(); - if (optionalCustomItem.isPresent() && optionalCustomItem.get().settings().dyeable() == Tristate.FALSE) { - inventory.setResult(null); - return; - } - } - } else { - inventory.setResult(null); return; } + // 其他配方不允许使用自定义物品 + inventory.setResult(null); } catch (Exception e) { - this.plugin.logger().warn("Failed to handle minecraft custom recipe", e); + this.plugin.logger().warn("Failed to handle custom recipe", e); } } @@ -776,7 +735,10 @@ public class RecipeEventListener implements Listener { if (itemStack == null) continue; if (first == null) { first = itemStack; - } else if (second == null) { + } else { + if (second != null) { + return null; + } second = itemStack; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 3298c5eba..8c8babf2e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -1,8 +1,11 @@ package net.momirealms.craftengine.bukkit.plugin.injector; import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; import net.bytebuddy.ByteBuddy; import net.bytebuddy.ClassFileVersion; +import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; import net.bytebuddy.implementation.FieldAccessor; @@ -10,8 +13,10 @@ import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.bind.annotation.AllArguments; import net.bytebuddy.implementation.bind.annotation.RuntimeType; import net.bytebuddy.implementation.bind.annotation.This; +import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatchers; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; @@ -21,12 +26,15 @@ import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.util.*; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Constructor; @@ -40,6 +48,8 @@ import java.util.function.Predicate; public class RecipeInjector { private static Class clazz$InjectedCacheChecker; private static Class clazz$InjectedArmorDyeRecipe; + private static Class clazz$InjectedRepairItemRecipe; + private static Class clazz$InjectedFireworkStarFadeRecipe; public static void init() { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); @@ -48,64 +58,96 @@ public class RecipeInjector { .name("net.momirealms.craftengine.bukkit.entity.InjectedCacheChecker") .implement(CoreReflections.clazz$RecipeManager$CachedCheck) .implement(InjectedCacheCheck.class) - .defineField("recipeType", Object.class, Visibility.PUBLIC) .method(ElementMatchers.named("recipeType")) .intercept(FieldAccessor.ofField("recipeType")) - .defineField("customRecipeType", Key.class, Visibility.PUBLIC) .method(ElementMatchers.named("customRecipeType")) .intercept(FieldAccessor.ofField("customRecipeType")) - .defineField("lastRecipe", Object.class, Visibility.PUBLIC) .method(ElementMatchers.named("lastRecipe")) .intercept(FieldAccessor.ofField("lastRecipe")) - .defineField("lastCustomRecipe", Key.class, Visibility.PUBLIC) .method(ElementMatchers.named("lastCustomRecipe")) .intercept(FieldAccessor.ofField("lastCustomRecipe")) - .method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a"))) .intercept(MethodDelegation.to( VersionHelper.isOrAbove1_21_2() ? - GetRecipeForMethodInterceptor1_21_2.INSTANCE : - (VersionHelper.isOrAbove1_21() ? - GetRecipeForMethodInterceptor1_21.INSTANCE : - VersionHelper.isOrAbove1_20_5() ? - GetRecipeForMethodInterceptor1_20_5.INSTANCE : - GetRecipeForMethodInterceptor1_20.INSTANCE) + GetRecipeForMethodInterceptor1_21_2.INSTANCE : + (VersionHelper.isOrAbove1_21() ? + GetRecipeForMethodInterceptor1_21.INSTANCE : + VersionHelper.isOrAbove1_20_5() ? + GetRecipeForMethodInterceptor1_20_5.INSTANCE : + GetRecipeForMethodInterceptor1_20.INSTANCE) )) .make() .load(RecipeInjector.class.getClassLoader()) .getLoaded(); + ElementMatcher.Junction matches = (VersionHelper.isOrAbove1_21() ? + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$Level) : + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$Level) + ).and(ElementMatchers.returns(boolean.class)); + ElementMatcher.Junction assemble = ( + VersionHelper.isOrAbove1_21() ? + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$HolderLookup$Provider) : + VersionHelper.isOrAbove1_20_5() ? + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$HolderLookup$Provider) : + ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$RegistryAccess) + ).and(ElementMatchers.returns(CoreReflections.clazz$ItemStack)); + clazz$InjectedArmorDyeRecipe = byteBuddy .subclass(CoreReflections.clazz$ArmorDyeRecipe, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) .name("net.momirealms.craftengine.bukkit.item.recipe.ArmorDyeRecipe") - .method((VersionHelper.isOrAbove1_21() ? - ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$Level) : - ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$Level) - ).and(ElementMatchers.returns(boolean.class))) - .intercept(MethodDelegation.to(MatchesInterceptor.INSTANCE)) - .method(( - VersionHelper.isOrAbove1_21() ? - ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$HolderLookup$Provider) : - VersionHelper.isOrAbove1_20_5() ? - ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$HolderLookup$Provider) : - ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$RegistryAccess) - ).and(ElementMatchers.returns(CoreReflections.clazz$ItemStack))) - .intercept(MethodDelegation.to(AssembleInterceptor.INSTANCE)) + .method(matches) + .intercept(MethodDelegation.to(DyeMatchesInterceptor.INSTANCE)) + .method(assemble) + .intercept(MethodDelegation.to(DyeAssembleInterceptor.INSTANCE)) + .make() + .load(RecipeInjector.class.getClassLoader()) + .getLoaded(); + + clazz$InjectedFireworkStarFadeRecipe = byteBuddy + .subclass(CoreReflections.clazz$FireworkStarFadeRecipe) + .name("net.momirealms.craftengine.bukkit.item.recipe.FireworkStarFadeRecipe") + .method(matches) + .intercept(MethodDelegation.to(FireworkStarFadeMatchesInterceptor.INSTANCE)) + .method(assemble) + .intercept(MethodDelegation.to(FireworkStarFadeAssembleInterceptor.INSTANCE)) + .make() + .load(RecipeInjector.class.getClassLoader()) + .getLoaded(); + + clazz$InjectedRepairItemRecipe = byteBuddy + .subclass(CoreReflections.clazz$RepairItemRecipe, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) + .name("net.momirealms.craftengine.bukkit.item.recipe.RepairItemRecipe") + // 只修改match逻辑,合并需要在事件里处理,否则无法应用变量 + .method(matches) + .intercept(MethodDelegation.to(RepairMatchesInterceptor.INSTANCE)) .make() .load(RecipeInjector.class.getClassLoader()) .getLoaded(); } - public static Object createCustomDyeRecipe() throws ReflectiveOperationException { + public static Object createRepairItemRecipe(Key id) throws ReflectiveOperationException { + return createSpecialRecipe(id, clazz$InjectedRepairItemRecipe); + } + + public static Object createCustomDyeRecipe(Key id) throws ReflectiveOperationException { + return createSpecialRecipe(id, clazz$InjectedArmorDyeRecipe); + } + + public static Object createFireworkStarFadeRecipe(Key id) throws ReflectiveOperationException { + return createSpecialRecipe(id, clazz$InjectedFireworkStarFadeRecipe); + } + + @NotNull + private static Object createSpecialRecipe(Key id, Class clazz$InjectedRepairItemRecipe) throws InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException { if (VersionHelper.isOrAbove1_20_2()) { - Constructor constructor = ReflectionUtils.getConstructor(clazz$InjectedArmorDyeRecipe, CoreReflections.clazz$CraftingBookCategory); + Constructor constructor = ReflectionUtils.getConstructor(clazz$InjectedRepairItemRecipe, CoreReflections.clazz$CraftingBookCategory); return constructor.newInstance(CoreReflections.instance$CraftingBookCategory$MISC); } else { - Constructor constructor = ReflectionUtils.getConstructor(clazz$InjectedArmorDyeRecipe, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$CraftingBookCategory); - return constructor.newInstance(KeyUtils.toResourceLocation(Key.of("armor_dye")), CoreReflections.instance$CraftingBookCategory$MISC); + Constructor constructor = ReflectionUtils.getConstructor(clazz$InjectedRepairItemRecipe, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$CraftingBookCategory); + return constructor.newInstance(KeyUtils.toResourceLocation(id), CoreReflections.instance$CraftingBookCategory$MISC); } } @@ -138,29 +180,161 @@ public class RecipeInjector { } } - private static final Function INGREDIENT_COUNT_CHECKER = + private static final Function INGREDIENT_SIZE_GETTER = VersionHelper.isOrAbove1_21() ? - (input) -> FastNMS.INSTANCE.method$CraftingInput$ingredientCount(input) < 2 : - (container) -> false; - private static final Function INGREDIENT_COUNT_GETTER = - VersionHelper.isOrAbove1_21() ? - FastNMS.INSTANCE::method$CraftingInput$ingredientCount : + FastNMS.INSTANCE::method$CraftingInput$size : FastNMS.INSTANCE::method$Container$getContainerSize; private static final BiFunction INGREDIENT_GETTER = VersionHelper.isOrAbove1_21() ? FastNMS.INSTANCE::method$CraftingInput$getItem : FastNMS.INSTANCE::method$Container$getItem; - public static class MatchesInterceptor { - public static final MatchesInterceptor INSTANCE = new MatchesInterceptor(); + private static final Function REPAIR_INGREDIENT_COUNT_CHECKER = + VersionHelper.isOrAbove1_21() ? + (input) -> FastNMS.INSTANCE.method$CraftingInput$ingredientCount(input) != 2 : + (container) -> false; + + public static class FireworkStarFadeMatchesInterceptor { + public static final FireworkStarFadeMatchesInterceptor INSTANCE = new FireworkStarFadeMatchesInterceptor(); @RuntimeType public Object intercept(@AllArguments Object[] args) { Object input = args[0]; - if (INGREDIENT_COUNT_CHECKER.apply(input)) { + if (DYE_INGREDIENT_COUNT_CHECKER.apply(input)) { return false; } - int size = INGREDIENT_COUNT_GETTER.apply(input); + boolean hasDye = false; + boolean hasFireworkStar = false; + int size = INGREDIENT_SIZE_GETTER.apply(input); + for (int i = 0; i < size; i++) { + Object itemStack = INGREDIENT_GETTER.apply(input, i); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) { + continue; + } + Item wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)); + if (isFireworkDye(wrapped)) { + hasDye = true; + } else { + if (!wrapped.id().equals(ItemKeys.FIREWORK_STAR)) { + return false; + } + if (hasFireworkStar) { + return false; + } + hasFireworkStar = true; + } + } + return hasDye && hasFireworkStar; + } + } + + public static class FireworkStarFadeAssembleInterceptor { + public static final FireworkStarFadeAssembleInterceptor INSTANCE = new FireworkStarFadeAssembleInterceptor(); + + @RuntimeType + public Object intercept(@AllArguments Object[] args) { + IntList colors = new IntArrayList(); + Item starItem = null; + Object input = args[0]; + int size = INGREDIENT_SIZE_GETTER.apply(input); + for (int i = 0; i < size; i++) { + Object itemStack = INGREDIENT_GETTER.apply(input, i); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) { + continue; + } + Item wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)); + if (isFireworkDye(wrapped)) { + Color color = getFireworkColor(wrapped); + if (color == null) { + return CoreReflections.instance$ItemStack$EMPTY; + } + colors.add(color.color()); + } else if (wrapped.id().equals(ItemKeys.FIREWORK_STAR)) { + starItem = wrapped.copyWithCount(1); + } + } + if (starItem == null || colors.isEmpty()) { + return CoreReflections.instance$ItemStack$EMPTY; + } + FireworkExplosion explosion = starItem.fireworkExplosion().orElse(FireworkExplosion.DEFAULT); + starItem.fireworkExplosion(explosion.withFadeColors(colors)); + return starItem.getLiteralObject(); + } + } + + public static class RepairMatchesInterceptor { + public static final RepairMatchesInterceptor INSTANCE = new RepairMatchesInterceptor(); + + @RuntimeType + public Object intercept(@AllArguments Object[] args) { + Object input = args[0]; + if (REPAIR_INGREDIENT_COUNT_CHECKER.apply(input)) { + return false; + } + return getItemsToCombine(input) != null; + } + } + + @Nullable + private static Pair, Item> getItemsToCombine(Object input) { + Item item1 = null; + Item item2 = null; + int size = INGREDIENT_SIZE_GETTER.apply(input); + for (int i = 0; i < size; i++) { + Object itemStack = INGREDIENT_GETTER.apply(input, i); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) { + continue; + } + Item wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)); + if (item1 == null) { + item1 = wrapped; + } else { + if (item2 != null) { + return null; + } + item2 = wrapped; + } + } + if (item1 == null || item2 == null) { + return null; + } + if (!canCombine(item1, item2)) { + return null; + } + return new Pair<>(item1, item2); + } + + private static boolean canCombine(Item input1, Item input2) { + if (input1.count() != 1 || !isDamageableItem(input1)) return false; + if (input2.count() != 1 || !isDamageableItem(input2)) return false; + if (!input1.id().equals(input2.id())) return false; + Optional> customItem = input1.getCustomItem(); + return customItem.isEmpty() || customItem.get().settings().canRepair() != Tristate.FALSE; + } + + private static boolean isDamageableItem(Item item) { + if (VersionHelper.isOrAbove1_20_5()) { + return item.hasComponent(ComponentTypes.MAX_DAMAGE) && item.hasComponent(ComponentTypes.DAMAGE); + } else { + return FastNMS.INSTANCE.method$Item$canBeDepleted(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject())); + } + } + + private static final Function DYE_INGREDIENT_COUNT_CHECKER = + VersionHelper.isOrAbove1_21() ? + (input) -> FastNMS.INSTANCE.method$CraftingInput$ingredientCount(input) < 2 : + (container) -> false; + + public static class DyeMatchesInterceptor { + public static final DyeMatchesInterceptor INSTANCE = new DyeMatchesInterceptor(); + + @RuntimeType + public Object intercept(@AllArguments Object[] args) { + Object input = args[0]; + if (DYE_INGREDIENT_COUNT_CHECKER.apply(input)) { + return false; + } + int size = INGREDIENT_SIZE_GETTER.apply(input); Item itemToDye = null; boolean hasDye = false; for (int i = 0; i < size; i++) { @@ -175,7 +349,7 @@ public class RecipeInjector { } itemToDye = wrapped; } else { - if (!isDye(wrapped)) { + if (!isArmorDye(wrapped)) { return false; } hasDye = true; @@ -185,15 +359,15 @@ public class RecipeInjector { } } - public static class AssembleInterceptor { - public static final AssembleInterceptor INSTANCE = new AssembleInterceptor(); + public static class DyeAssembleInterceptor { + public static final DyeAssembleInterceptor INSTANCE = new DyeAssembleInterceptor(); @RuntimeType public Object intercept(@AllArguments Object[] args) { List colors = new ArrayList<>(); Item itemToDye = null; Object input = args[0]; - int size = INGREDIENT_COUNT_GETTER.apply(input); + int size = INGREDIENT_SIZE_GETTER.apply(input); for (int i = 0; i < size; i++) { Object itemStack = INGREDIENT_GETTER.apply(input, i); if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) { @@ -212,7 +386,7 @@ public class RecipeInjector { } } if (itemToDye == null || itemToDye.isEmpty() || colors.isEmpty()) { - return null; + return CoreReflections.instance$ItemStack$EMPTY; } return itemToDye.applyDyedColors(colors).getLiteralObject(); } @@ -228,6 +402,16 @@ public class RecipeInjector { return getVanillaDyeColor(dyeItem); } + @Nullable + private static Color getFireworkColor(final Item dyeItem) { + Optional> optionalCustomItem = dyeItem.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + return Optional.ofNullable(customItem.settings().fireworkColor()).orElseGet(() -> getVanillaFireworkColor(dyeItem)); + } + return getVanillaFireworkColor(dyeItem); + } + private static final Predicate> IS_DYEABLE = VersionHelper.isOrAbove1_20_5() ? (item -> item.is(ItemTags.DYEABLE)) : @@ -258,7 +442,15 @@ public class RecipeInjector { return Color.fromDecimal(FastNMS.INSTANCE.method$DyeColor$getTextureDiffuseColor(FastNMS.INSTANCE.method$DyeItem$getDyeColor(dyeItem))); } - private static boolean isDye(Item dyeItem) { + @Nullable + private static Color getVanillaFireworkColor(final Item item) { + Object itemStack = item.getLiteralObject(); + Object dyeItem = FastNMS.INSTANCE.method$ItemStack$getItem(itemStack); + if (!CoreReflections.clazz$DyeItem.isInstance(dyeItem)) return null; + return Color.fromDecimal(FastNMS.INSTANCE.method$DyeColor$getFireworkColor(FastNMS.INSTANCE.method$DyeItem$getDyeColor(dyeItem))); + } + + private static boolean isArmorDye(Item dyeItem) { Optional> optionalCustomItem = dyeItem.getCustomItem(); if (optionalCustomItem.isPresent()) { CustomItem customItem = optionalCustomItem.get(); @@ -267,6 +459,15 @@ public class RecipeInjector { return isVanillaDyeItem(dyeItem); } + private static boolean isFireworkDye(Item dyeItem) { + Optional> optionalCustomItem = dyeItem.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + return customItem.settings().fireworkColor() != null || isVanillaDyeItem(dyeItem); + } + return isVanillaDyeItem(dyeItem); + } + private static boolean isVanillaDyeItem(Item item) { return CoreReflections.clazz$DyeItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject())); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 841487680..cf0c172e5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -60,6 +60,7 @@ public final class ItemKeys { public static final Key GREEN_DYE = Key.of("minecraft:green_dye"); public static final Key RED_DYE = Key.of("minecraft:red_dye"); public static final Key BLACK_DYE = Key.of("minecraft:black_dye"); + public static final Key FIREWORK_STAR = Key.of("minecraft:firework_star"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index 526f00969..f8d5ad125 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -25,7 +25,7 @@ import java.util.stream.Collectors; public class ItemSettings { int fuelTime; Set tags = Set.of(); - boolean canRepair = true; + Tristate canRepair = Tristate.UNDEFINED; List anvilRepairItems = List.of(); boolean renameable = true; boolean canPlaceRelatedVanillaBlock = false; @@ -43,6 +43,8 @@ public class ItemSettings { ItemEquipment equipment; @Nullable Color dyeColor; + @Nullable + Color fireworkColor; private ItemSettings() {} @@ -102,6 +104,7 @@ public class ItemSettings { newSettings.compostProbability = settings.compostProbability; newSettings.respectRepairableComponent = settings.respectRepairableComponent; newSettings.dyeColor = settings.dyeColor; + newSettings.fireworkColor = settings.fireworkColor; return newSettings; } @@ -125,7 +128,7 @@ public class ItemSettings { return canPlaceRelatedVanillaBlock; } - public boolean canRepair() { + public Tristate canRepair() { return canRepair; } @@ -184,7 +187,12 @@ public class ItemSettings { @Nullable public Color dyeColor() { - return dyeColor; + return this.dyeColor; + } + + @Nullable + public Color fireworkColor() { + return this.fireworkColor; } public List invulnerable() { @@ -195,6 +203,11 @@ public class ItemSettings { return compostProbability; } + public ItemSettings fireworkColor(Color color) { + this.fireworkColor = color; + return this; + } + public ItemSettings dyeColor(Color color) { this.dyeColor = color; return this; @@ -220,7 +233,7 @@ public class ItemSettings { return this; } - public ItemSettings canRepair(boolean canRepair) { + public ItemSettings canRepair(Tristate canRepair) { this.canRepair = canRepair; return this; } @@ -303,7 +316,7 @@ public class ItemSettings { static { registerFactory("repairable", (value -> { boolean bool = ResourceConfigUtils.getAsBoolean(value, "repairable"); - return settings -> settings.canRepair(bool); + return settings -> settings.canRepair(bool ? Tristate.TRUE : Tristate.FALSE); })); registerFactory("enchantable", (value -> { boolean bool = ResourceConfigUtils.getAsBoolean(value, "enchantable"); @@ -416,6 +429,13 @@ public class ItemSettings { return settings -> settings.dyeColor(Color.fromVector3f(MiscUtils.getAsVector3f(value, "dye-color"))); } })); + registerFactory("firework-color", (value -> { + if (value instanceof Integer i) { + return settings -> settings.fireworkColor(Color.fromDecimal(i)); + } else { + return settings -> settings.fireworkColor(Color.fromVector3f(MiscUtils.getAsVector3f(value, "firework-color"))); + } + })); registerFactory("food", (value -> { Map args = MiscUtils.castToMap(value, false); FoodData data = new FoodData( diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/data/FireworkExplosion.java b/core/src/main/java/net/momirealms/craftengine/core/item/data/FireworkExplosion.java index bad976667..279f51799 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/data/FireworkExplosion.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/data/FireworkExplosion.java @@ -8,6 +8,12 @@ import java.util.Map; public record FireworkExplosion(Shape shape, IntList colors, IntList fadeColors, boolean hasTrail, boolean hasTwinkle) { + public static final FireworkExplosion DEFAULT = new FireworkExplosion(Shape.SMALL_BALL, IntList.of(), IntList.of(), false, false); + + public FireworkExplosion withFadeColors(@NotNull final IntList fadeColors) { + return new FireworkExplosion(this.shape, this.colors, fadeColors, this.hasTrail, this.hasTwinkle); + } + public enum Shape { SMALL_BALL(0, "small_ball"), LARGE_BALL(1, "large_ball"), diff --git a/gradle.properties b/gradle.properties index 1d95c9947..837b678ab 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.9 +project_version=0.0.60.10 config_version=43 lang_version=23 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.18 -nms_helper_version=1.0.46 +nms_helper_version=1.0.48 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 36cc67bcefdfabc4cf5f8026349a7af9a6e95f94 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 2 Aug 2025 01:27:05 +0800 Subject: [PATCH 71/83] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=9B=B4=E9=AB=98?= =?UTF-8?q?=E6=95=88=E7=9A=84=E5=90=88=E6=88=90=E9=85=8D=E6=96=B9=E5=88=A4?= =?UTF-8?q?=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/BukkitRecipeManager.java | 24 +++++++-------- .../item/recipe/CrafterEventListener.java | 9 ++---- .../item/recipe/RecipeEventListener.java | 30 +++++++------------ .../plugin/injector/InjectedCacheCheck.java | 5 ++-- .../plugin/injector/RecipeInjector.java | 12 ++++---- .../bukkit/util/InteractUtils.java | 6 ++-- .../item/recipe/AbstractRecipeManager.java | 10 +++---- .../item/recipe/CustomBlastingRecipe.java | 9 ++++-- .../core/item/recipe/CustomBrewingRecipe.java | 9 ++++-- .../item/recipe/CustomCampfireRecipe.java | 9 ++++-- .../recipe/CustomCraftingTableRecipe.java | 5 ++++ .../core/item/recipe/CustomShapedRecipe.java | 4 +-- .../item/recipe/CustomShapelessRecipe.java | 4 +-- .../item/recipe/CustomSmeltingRecipe.java | 9 ++++-- .../recipe/CustomSmithingTransformRecipe.java | 9 ++++-- .../item/recipe/CustomSmithingTrimRecipe.java | 9 ++++-- .../core/item/recipe/CustomSmokingRecipe.java | 9 ++++-- .../item/recipe/CustomStoneCuttingRecipe.java | 9 ++++-- .../craftengine/core/item/recipe/Recipe.java | 4 ++- .../core/item/recipe/RecipeManager.java | 6 ++-- ...ecipeTypes.java => RecipeSerializers.java} | 3 +- .../core/item/recipe/RecipeType.java | 22 ++++++++++++++ .../recipe/vanilla/VanillaBlastingRecipe.java | 4 +-- .../recipe/vanilla/VanillaCampfireRecipe.java | 4 +-- .../recipe/vanilla/VanillaShapedRecipe.java | 4 +-- .../vanilla/VanillaShapelessRecipe.java | 4 +-- .../recipe/vanilla/VanillaSmeltingRecipe.java | 4 +-- .../VanillaSmithingTransformRecipe.java | 4 +-- .../vanilla/VanillaSmithingTrimRecipe.java | 4 +-- .../recipe/vanilla/VanillaSmokingRecipe.java | 4 +-- .../vanilla/VanillaStoneCuttingRecipe.java | 4 +-- .../gui/category/ItemBrowserManagerImpl.java | 20 ++++++------- 32 files changed, 163 insertions(+), 109 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/item/recipe/{RecipeTypes.java => RecipeSerializers.java} (96%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeType.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 0b018c5aa..b0af3b91c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -174,7 +174,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } static { - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRANSFORM, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMITHING_TRANSFORM, (BukkitRecipeConvertor>) (id, recipe) -> { try { Object nmsRecipe = createMinecraftSmithingTransformRecipe(recipe); return () -> MINECRAFT_RECIPE_ADDER.accept(id, nmsRecipe); @@ -185,7 +185,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { return null; } }); - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRIM, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMITHING_TRIM, (BukkitRecipeConvertor>) (id, recipe) -> { try { Object nmsRecipe = createMinecraftSmithingTrimRecipe(recipe); return () -> MINECRAFT_RECIPE_ADDER.accept(id, nmsRecipe); @@ -197,7 +197,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } }); // TODO DO NOT USE BUKKIT RECIPE AS BRIDGE IN FUTURE VERSIONS, WE SHOULD DIRECTLY CONSTRUCT THOSE NMS RECIPES - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPED, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SHAPED, (BukkitRecipeConvertor>) (id, recipe) -> { ShapedRecipe shapedRecipe = new ShapedRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); if (recipe.group() != null) shapedRecipe.setGroup(Objects.requireNonNull(recipe.group())); if (recipe.category() != null) shapedRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); @@ -210,7 +210,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { injectShapedRecipe(id, recipe); }; }); - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPELESS, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SHAPELESS, (BukkitRecipeConvertor>) (id, recipe) -> { ShapelessRecipe shapelessRecipe = new ShapelessRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); if (recipe.group() != null) shapelessRecipe.setGroup(Objects.requireNonNull(recipe.group())); if (recipe.category() != null) shapelessRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); @@ -222,7 +222,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { injectShapelessRecipe(id, recipe); }; }); - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMELTING, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMELTING, (BukkitRecipeConvertor>) (id, recipe) -> { FurnaceRecipe furnaceRecipe = new FurnaceRecipe( new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), ingredientToBukkitRecipeChoice(recipe.ingredient()), @@ -235,7 +235,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { injectCookingRecipe(id, recipe); }; }); - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMOKING, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMOKING, (BukkitRecipeConvertor>) (id, recipe) -> { SmokingRecipe smokingRecipe = new SmokingRecipe( new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), ingredientToBukkitRecipeChoice(recipe.ingredient()), @@ -248,7 +248,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { injectCookingRecipe(id, recipe); }; }); - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.BLASTING, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.BLASTING, (BukkitRecipeConvertor>) (id, recipe) -> { BlastingRecipe blastingRecipe = new BlastingRecipe( new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), ingredientToBukkitRecipeChoice(recipe.ingredient()), @@ -261,7 +261,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { injectCookingRecipe(id, recipe); }; }); - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.CAMPFIRE_COOKING, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.CAMPFIRE_COOKING, (BukkitRecipeConvertor>) (id, recipe) -> { CampfireRecipe campfireRecipe = new CampfireRecipe( new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), ingredientToBukkitRecipeChoice(recipe.ingredient()), @@ -274,7 +274,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { injectCookingRecipe(id, recipe); }; }); - MIXED_RECIPE_CONVERTORS.put(RecipeTypes.STONECUTTING, (BukkitRecipeConvertor>) (id, recipe) -> { + MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.STONECUTTING, (BukkitRecipeConvertor>) (id, recipe) -> { List itemStacks = new ArrayList<>(); for (UniqueKey item : recipe.ingredient().items()) { itemStacks.add(BukkitItemManager.instance().buildItemStack(item.key(), null)); @@ -304,10 +304,10 @@ public class BukkitRecipeManager extends AbstractRecipeManager { private final BukkitCraftEngine plugin; private final RecipeEventListener recipeEventListener; private final CrafterEventListener crafterEventListener; - // To optimize recipes loading, will return the flag later - private Object stolenFeatureFlagSet; // Some delayed tasks on main thread private final List delayedTasksOnMainThread = new ArrayList<>(); + // To optimize recipes loading, will return the flag later + private Object stolenFeatureFlagSet; public BukkitRecipeManager(BukkitCraftEngine plugin) { instance = this; @@ -431,7 +431,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @SuppressWarnings("unchecked") private > BukkitRecipeConvertor findNMSRecipeConvertor(T recipe) { - return (BukkitRecipeConvertor) MIXED_RECIPE_CONVERTORS.get(recipe.type()); + return (BukkitRecipeConvertor) MIXED_RECIPE_CONVERTORS.get(recipe.serializerType()); } @SuppressWarnings("unchecked") diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java index 5b5d2fd37..6fb03e8ec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.recipe.Recipe; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeType; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.plugin.config.Config; @@ -71,12 +71,7 @@ public class CrafterEventListener implements Listener { return; } - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input); - if (ceRecipe != null) { - event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY)); - return; - } - ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.CRAFTING, input); if (ceRecipe != null) { event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY)); return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 2eb25c028..ceb1036ee 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -75,13 +75,13 @@ public class RecipeEventListener implements Listener { if (ItemStackUtils.isEmpty(item)) return; if (ItemStackUtils.isEmpty(fuelStack)) { SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(item)); - Key recipeType; + RecipeType recipeType; if (furnaceInventory.getType() == InventoryType.FURNACE) { - recipeType = RecipeTypes.SMELTING; + recipeType = RecipeType.SMELTING; } else if (furnaceInventory.getType() == InventoryType.BLAST_FURNACE) { - recipeType = RecipeTypes.BLASTING; + recipeType = RecipeType.BLASTING; } else { - recipeType = RecipeTypes.SMOKING; + recipeType = RecipeType.SMOKING; } Recipe ceRecipe = this.recipeManager.recipeByInput(recipeType, input); @@ -352,7 +352,7 @@ public class RecipeEventListener implements Listener { return; } SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeType.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); } @@ -377,7 +377,7 @@ public class RecipeEventListener implements Listener { ItemStack itemStack = event.getSource(); SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeType.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setTotalCookTime(Integer.MAX_VALUE); return; @@ -405,7 +405,7 @@ public class RecipeEventListener implements Listener { ItemStack itemStack = event.getSource(); SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeType.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); return; @@ -815,18 +815,8 @@ public class RecipeEventListener implements Listener { Player player = InventoryUtils.getPlayerFromInventoryEvent(event); BukkitServerPlayer serverPlayer = this.plugin.adapt(player); - Key lastRecipe = serverPlayer.lastUsedRecipe(); - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input, lastRecipe); - if (ceRecipe != null) { - inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); - serverPlayer.setLastUsedRecipe(ceRecipe.id()); - if (!ceRecipe.id().equals(recipeId)) { - correctCraftingRecipeUsed(inventory, ceRecipe); - } - return; - } - ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.CRAFTING, input, recipeId); if (ceRecipe != null) { inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); @@ -902,7 +892,7 @@ public class RecipeEventListener implements Listener { getUniqueIdItem(inventory.getInputMineral()) ); - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRIM, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.SMITHING, input, recipeId); if (ceRecipe == null) { event.setResult(null); return; @@ -940,7 +930,7 @@ public class RecipeEventListener implements Listener { getUniqueIdItem(addition) ); - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRANSFORM, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.SMITHING, input, recipeId); if (ceRecipe == null) { event.setResult(null); return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java index f8fc33654..03ff73844 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.injector; +import net.momirealms.craftengine.core.item.recipe.RecipeType; import net.momirealms.craftengine.core.util.Key; public interface InjectedCacheCheck { @@ -8,9 +9,9 @@ public interface InjectedCacheCheck { void recipeType(Object recipeType); - Key customRecipeType(); + RecipeType customRecipeType(); - void customRecipeType(Key customRecipeType); + void customRecipeType(RecipeType customRecipeType); Object lastRecipe(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 8c8babf2e..63ad89c4b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -29,7 +29,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeType; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.util.*; @@ -61,7 +61,7 @@ public class RecipeInjector { .defineField("recipeType", Object.class, Visibility.PUBLIC) .method(ElementMatchers.named("recipeType")) .intercept(FieldAccessor.ofField("recipeType")) - .defineField("customRecipeType", Key.class, Visibility.PUBLIC) + .defineField("customRecipeType", RecipeType.class, Visibility.PUBLIC) .method(ElementMatchers.named("customRecipeType")) .intercept(FieldAccessor.ofField("customRecipeType")) .defineField("lastRecipe", Object.class, Visibility.PUBLIC) @@ -158,13 +158,13 @@ public class RecipeInjector { Object recipeType = FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$recipeType(entity); InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); if (recipeType == MRecipeTypes.SMELTING) { - injectedChecker.customRecipeType(RecipeTypes.SMELTING); + injectedChecker.customRecipeType(RecipeType.SMELTING); injectedChecker.recipeType(MRecipeTypes.SMELTING); } else if (recipeType == MRecipeTypes.BLASTING) { - injectedChecker.customRecipeType(RecipeTypes.BLASTING); + injectedChecker.customRecipeType(RecipeType.BLASTING); injectedChecker.recipeType(MRecipeTypes.BLASTING); } else if (recipeType == MRecipeTypes.SMOKING) { - injectedChecker.customRecipeType(RecipeTypes.SMOKING); + injectedChecker.customRecipeType(RecipeType.SMOKING); injectedChecker.recipeType(MRecipeTypes.SMOKING); } else { throw new IllegalStateException("RecipeType " + recipeType + " not supported"); @@ -174,7 +174,7 @@ public class RecipeInjector { Object quickCheck = CoreReflections.field$CampfireBlockEntity$quickCheck.get(entity); if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); - injectedChecker.customRecipeType(RecipeTypes.CAMPFIRE_COOKING); + injectedChecker.customRecipeType(RecipeType.CAMPFIRE_COOKING); injectedChecker.recipeType(MRecipeTypes.CAMPFIRE_COOKING); CoreReflections.field$CampfireBlockEntity$quickCheck.set(entity, injectedChecker); } 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 b9f6c5556..2bbe31a7a 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 @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.entity.EntityTypeKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeType; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -129,13 +129,13 @@ public class InteractUtils { }); registerInteraction(BlockKeys.SOUL_CAMPFIRE, (player, item, blockState, result) -> { if (!Config.enableRecipeSystem()) return false; - return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( + return BukkitRecipeManager.instance().recipeByInput(RecipeType.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( item.recipeIngredientId(), item ))) != null; }); registerInteraction(BlockKeys.CAMPFIRE, (player, item, blockState, result) -> { if (!Config.enableRecipeSystem()) return false; - return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( + return BukkitRecipeManager.instance().recipeByInput(RecipeType.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( item.recipeIngredientId(), item ))) != null; }); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java index b39dbb002..5334d96ae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -22,7 +22,7 @@ import java.util.*; public abstract class AbstractRecipeManager implements RecipeManager { protected final VanillaRecipeReader recipeReader; - protected final Map>> byType = new HashMap<>(); + protected final Map>> byType = new HashMap<>(); protected final Map> byId = new HashMap<>(); protected final Map>> byResult = new HashMap<>(); protected final Map>> byIngredient = new HashMap<>(); @@ -84,7 +84,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { } @Override - public List> recipesByType(Key type) { + public List> recipesByType(RecipeType type) { if (this.isReloading) return List.of(); return this.byType.getOrDefault(type, List.of()); } @@ -103,7 +103,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { @Nullable @Override - public Recipe recipeByInput(Key type, RecipeInput input) { + public Recipe recipeByInput(RecipeType type, RecipeInput input) { if (this.isReloading) return null; List> recipes = this.byType.get(type); if (recipes == null) return null; @@ -117,7 +117,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { @Nullable @Override - public Recipe recipeByInput(Key type, RecipeInput input, Key lastRecipe) { + public Recipe recipeByInput(RecipeType type, RecipeInput input, Key lastRecipe) { if (this.isReloading) return null; if (lastRecipe != null) { Recipe last = this.byId.get(lastRecipe); @@ -164,7 +164,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { if (AbstractRecipeManager.this.byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.recipe.duplicate", path, id); } - Recipe recipe = RecipeTypes.fromMap(id, section); + Recipe recipe = RecipeSerializers.fromMap(id, section); try { registerInternalRecipe(id, recipe); registerPlatformRecipe(id, recipe); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java index 127d5a6b4..2ab483f74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java @@ -16,8 +16,13 @@ public class CustomBlastingRecipe extends CustomCookingRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.BLASTING; + public @NotNull Key serializerType() { + return RecipeSerializers.BLASTING; + } + + @Override + public RecipeType type() { + return RecipeType.BLASTING; } public static class Factory extends AbstractRecipeFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java index 1b622acfc..012eefc78 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java @@ -56,8 +56,13 @@ public class CustomBrewingRecipe implements FixedResultRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.BREWING; + public @NotNull Key serializerType() { + return RecipeSerializers.BREWING; + } + + @Override + public RecipeType type() { + return RecipeType.BREWING; } @NotNull diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java index 38d7e5aff..6f34328fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java @@ -16,8 +16,13 @@ public class CustomCampfireRecipe extends CustomCookingRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.CAMPFIRE_COOKING; + public @NotNull Key serializerType() { + return RecipeSerializers.CAMPFIRE_COOKING; + } + + @Override + public RecipeType type() { + return RecipeType.CAMPFIRE_COOKING; } public static class Factory extends AbstractRecipeFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java index 866a2db07..5d2c241fe 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java @@ -13,4 +13,9 @@ public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe public CraftingRecipeCategory category() { return category; } + + @Override + public RecipeType type() { + return RecipeType.CRAFTING; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java index 2350a975b..274a2e5a8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java @@ -38,8 +38,8 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.SHAPED; + public @NotNull Key serializerType() { + return RecipeSerializers.SHAPED; } public Pattern pattern() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java index 5ff9494e0..aae980768 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java @@ -47,8 +47,8 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.SHAPELESS; + public @NotNull Key serializerType() { + return RecipeSerializers.SHAPELESS; } public static class Factory extends AbstractRecipeFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java index 8d7c2be96..ef0dc9a6c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java @@ -16,8 +16,13 @@ public class CustomSmeltingRecipe extends CustomCookingRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.SMELTING; + public @NotNull Key serializerType() { + return RecipeSerializers.SMELTING; + } + + @Override + public RecipeType type() { + return RecipeType.SMELTING; } public static class Factory extends AbstractRecipeFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index ae26068cd..80bafeccf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -78,8 +78,13 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.SMITHING_TRANSFORM; + public @NotNull Key serializerType() { + return RecipeSerializers.SMITHING_TRANSFORM; + } + + @Override + public RecipeType type() { + return RecipeType.SMITHING; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java index 993fb1a31..18d1b7062 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java @@ -80,8 +80,13 @@ public class CustomSmithingTrimRecipe implements Recipe { } @Override - public @NotNull Key type() { - return RecipeTypes.SMITHING_TRIM; + public @NotNull Key serializerType() { + return RecipeSerializers.SMITHING_TRIM; + } + + @Override + public RecipeType type() { + return RecipeType.SMITHING; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java index 83939ac29..1ea3590af 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java @@ -16,8 +16,13 @@ public class CustomSmokingRecipe extends CustomCookingRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.SMOKING; + public @NotNull Key serializerType() { + return RecipeSerializers.SMOKING; + } + + @Override + public RecipeType type() { + return RecipeType.SMOKING; } public static class Factory extends AbstractRecipeFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java index 95e91ef77..485dc6b74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java @@ -31,8 +31,13 @@ public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { } @Override - public @NotNull Key type() { - return RecipeTypes.STONECUTTING; + public @NotNull Key serializerType() { + return RecipeSerializers.STONECUTTING; + } + + @Override + public RecipeType type() { + return RecipeType.STONECUTTING; } public Ingredient ingredient() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java index a07812c06..2068a735b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java @@ -16,7 +16,9 @@ public interface Recipe { List> ingredientsInUse(); @NotNull - Key type(); + Key serializerType(); + + RecipeType type(); Key id(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java index c1fdcdbc3..fbe916176 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java @@ -19,15 +19,15 @@ public interface RecipeManager extends Manageable { Optional> recipeById(Key id); - List> recipesByType(Key type); + List> recipesByType(RecipeType type); List> recipeByResult(Key result); List> recipeByIngredient(Key ingredient); @Nullable - Recipe recipeByInput(Key type, RecipeInput input); + Recipe recipeByInput(RecipeType type, RecipeInput input); @Nullable - Recipe recipeByInput(Key type, RecipeInput input, @Nullable Key lastRecipe); + Recipe recipeByInput(RecipeType type, RecipeInput input, @Nullable Key lastRecipe); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializers.java similarity index 96% rename from core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java rename to core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializers.java index d4b7ee61a..4ba3385db 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializers.java @@ -10,7 +10,7 @@ import net.momirealms.craftengine.core.util.ResourceKey; import java.util.Map; -public class RecipeTypes { +public final class RecipeSerializers { public static final Key SHAPED = Key.of("minecraft:shaped"); public static final Key SHAPELESS = Key.of("minecraft:shapeless"); public static final Key SMELTING = Key.of("minecraft:smelting"); @@ -21,7 +21,6 @@ public class RecipeTypes { public static final Key SMITHING_TRANSFORM = Key.of("minecraft:smithing_transform"); public static final Key SMITHING_TRIM = Key.of("minecraft:smithing_trim"); public static final Key BREWING = Key.of("minecraft:brewing"); - public static final Key SPECIAL = Key.of("minecraft:special"); static { register(SHAPED, CustomShapedRecipe.FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeType.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeType.java new file mode 100644 index 000000000..1d86dafd7 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeType.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.item.recipe; + +public enum RecipeType { + CRAFTING("crafting"), + SMELTING("smelting"), + BLASTING("blasting"), + SMOKING("smoking"), + CAMPFIRE_COOKING("campfire_cooking"), + STONECUTTING("stonecutting"), + BREWING("brewing"), + SMITHING("smithing"); + + private final String id; + + RecipeType(String id) { + this.id = id; + } + + public String id() { + return id; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java index a78b6bb0c..bacbaa854 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -14,6 +14,6 @@ public class VanillaBlastingRecipe extends VanillaCookingRecipe { @Override public Key type() { - return RecipeTypes.BLASTING; + return RecipeSerializers.BLASTING; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java index aa12d79db..5a2b1624a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -14,6 +14,6 @@ public class VanillaCampfireRecipe extends VanillaCookingRecipe { @Override public Key type() { - return RecipeTypes.CAMPFIRE_COOKING; + return RecipeSerializers.CAMPFIRE_COOKING; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java index 753590f5c..bedb18ef2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -31,6 +31,6 @@ public class VanillaShapedRecipe extends VanillaCraftingRecipe { @Override public Key type() { - return RecipeTypes.SHAPED; + return RecipeSerializers.SHAPED; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java index 2e06b2988..1c2c912c3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -20,6 +20,6 @@ public class VanillaShapelessRecipe extends VanillaCraftingRecipe { @Override public Key type() { - return RecipeTypes.SHAPELESS; + return RecipeSerializers.SHAPELESS; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java index ebbed4b21..34db78614 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -14,6 +14,6 @@ public class VanillaSmeltingRecipe extends VanillaCookingRecipe { @Override public Key type() { - return RecipeTypes.SMELTING; + return RecipeSerializers.SMELTING; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java index fef4ffbda..213d352e8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -20,7 +20,7 @@ public class VanillaSmithingTransformRecipe implements VanillaRecipe { @Override public Key type() { - return RecipeTypes.SMITHING_TRANSFORM; + return RecipeSerializers.SMITHING_TRANSFORM; } public RecipeResult result() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java index 4b6bee14d..432b131c2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -23,7 +23,7 @@ public class VanillaSmithingTrimRecipe implements VanillaRecipe { @Override public Key type() { - return RecipeTypes.SMITHING_TRIM; + return RecipeSerializers.SMITHING_TRIM; } public List base() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java index 736a3fd5e..fbb262398 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -14,6 +14,6 @@ public class VanillaSmokingRecipe extends VanillaCookingRecipe { @Override public Key type() { - return RecipeTypes.SMOKING; + return RecipeSerializers.SMOKING; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java index 864557c68..6770a90c9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; -import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -19,6 +19,6 @@ public class VanillaStoneCuttingRecipe extends VanillaGroupedRecipe { @Override public Key type() { - return RecipeTypes.STONECUTTING; + return RecipeSerializers.STONECUTTING; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index e51058d2f..fd5b95839 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -392,24 +392,24 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { if (index >= recipes.size()) return; if (depth > MAX_RECIPE_DEPTH) return; Recipe recipe = recipes.get(index); - Key recipeType = recipe.type(); - if (recipeType == RecipeTypes.SHAPELESS || recipeType == RecipeTypes.SHAPED) { + Key recipeType = recipe.serializerType(); + if (recipeType == RecipeSerializers.SHAPELESS || recipeType == RecipeSerializers.SHAPED) { openCraftingRecipePage(player, (CustomCraftingTableRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); return; } - if (recipeType == RecipeTypes.BLASTING || recipeType == RecipeTypes.CAMPFIRE_COOKING || recipeType == RecipeTypes.SMOKING || recipeType == RecipeTypes.SMELTING) { + if (recipeType == RecipeSerializers.BLASTING || recipeType == RecipeSerializers.CAMPFIRE_COOKING || recipeType == RecipeSerializers.SMOKING || recipeType == RecipeSerializers.SMELTING) { openCookingRecipePage(player, (CustomCookingRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); return; } - if (recipeType == RecipeTypes.STONECUTTING) { + if (recipeType == RecipeSerializers.STONECUTTING) { openStoneCuttingRecipePage(player, (CustomStoneCuttingRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); return; } - if (recipeType == RecipeTypes.SMITHING_TRANSFORM) { + if (recipeType == RecipeSerializers.SMITHING_TRANSFORM) { openSmithingTransformRecipePage(player, (CustomSmithingTransformRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); return; } - if (recipeType == RecipeTypes.BREWING) { + if (recipeType == RecipeSerializers.BREWING) { openBrewingRecipePage(player, (CustomBrewingRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); return; } @@ -1041,11 +1041,11 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { })); String title; - if (recipe.type() == RecipeTypes.SMELTING) { + if (recipe.serializerType() == RecipeSerializers.SMELTING) { title = Constants.RECIPE_SMELTING_TITLE; - } else if (recipe.type() == RecipeTypes.BLASTING) { + } else if (recipe.serializerType() == RecipeSerializers.BLASTING) { title = Constants.RECIPE_BLASTING_TITLE; - } else if (recipe.type() == RecipeTypes.CAMPFIRE_COOKING) { + } else if (recipe.serializerType() == RecipeSerializers.CAMPFIRE_COOKING) { title = Constants.RECIPE_CAMPFIRE_TITLE; } else { title = Constants.RECIPE_SMOKING_TITLE; @@ -1154,7 +1154,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { })); char start = 'A'; - if (recipe.type() == RecipeTypes.SHAPED) { + if (recipe.serializerType() == RecipeSerializers.SHAPED) { String[] pattern = ((CustomShapedRecipe) recipe).pattern().pattern(); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { From 69a397e479e9707b278c552489c459a302964ea6 Mon Sep 17 00:00:00 2001 From: tamashii Date: Sat, 2 Aug 2025 23:17:38 +0200 Subject: [PATCH 72/83] A german translatsion update. --- .../src/main/resources/translations/de.yml | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 863854368..9b16042f2 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -65,6 +65,7 @@ command.send_resource_pack.success.single: "Ressourcenpaket an ge command.send_resource_pack.success.multiple: "Ressourcenpakete an Spieler gesendet." warning.config.pack.duplicated_files: "Duplizierte Dateien gefunden. Bitte beheben Sie diese im Abschnitt 'resource-pack.duplicated-files-handler' in config.yml." warning.config.yaml.duplicated_key: "Problem in Datei gefunden - Duplizierter Schlüssel '' in Zeile gefunden, dies kann zu unerwarteten Ergebnissen führen." +warning.config.yaml.inconsistent_value_type: "Fehler in der Datei - Der duplizierte Schlüssel '' wurde in Zeile mit einem anderen Werttyp gefunden. Dies könnte zu unerwarteten Ergebnissen führen." warning.config.type.int: "Problem in Datei gefunden - Laden von '' fehlgeschlagen: Kann '' nicht in den Integer-Typ für Option '' umwandeln." warning.config.type.float: "Problem in Datei gefunden - Laden von '' fehlgeschlagen: Kann '' nicht in den Float-Typ für Option '' umwandeln." warning.config.type.double: "Problem in Datei gefunden - Laden von '' fehlgeschlagen: Kann '' nicht in den Double-Typ für Option '' umwandeln." @@ -378,7 +379,6 @@ warning.config.function.remove_cooldown.missing_id: "Problem in Datei Problem in Datei gefunden - Der Konfiguration '' fehlt das erforderliche 'type'-Argument für den Selektor." warning.config.selector.invalid_type: "Problem in Datei gefunden - Die Konfiguration '' verwendet einen ungültigen Selektortyp ''." warning.config.selector.invalid_target: "Problem in Datei gefunden - Die Konfiguration '' verwendet ein ungültiges Selektorziel ''." -warning.config.resource_pack.item_model.conflict.vanilla: "Fehler beim Generieren des Gegenstandsmodells für '' da dieses Gegenstandsmodell von einem Vanilla-Gegenstand belegt wurde." warning.config.resource_pack.item_model.already_exist: "Fehler beim Generieren des Gegenstandsmodells für '' da die Datei '' bereits existiert." warning.config.resource_pack.model.generation.already_exist: "Fehler beim Generieren des Modells, da die Modelldatei '' bereits existiert." warning.config.resource_pack.generation.missing_font_texture: "Schriftart '' fehlt die erforderliche Textur: ''" @@ -388,3 +388,32 @@ warning.config.resource_pack.generation.missing_block_model: "Block 'Modell '' kann das Elternmodell nicht finden: ''" warning.config.resource_pack.generation.malformatted_json: "Json-Datei '' ist fehlerhaft formatiert." warning.config.resource_pack.invalid_overlay_format: "Problem in config.yml gefunden - Ungültiges Overlay-Format '' im Abschnitt 'resource-pack'. Unterstützte Overlays: []" +warning.config.type.map: "Fehler in der Datei - Das Laden von '' ist fehlgeschlagen: Kann den Typ '' nicht in den Typ 'Map' für die Option '' umwandeln." +warning.config.recipe.missing_pattern: "Fehler in der Datei - Dem geformten Rezept '' fehlt das erforderliche Argument 'pattern'." +warning.config.recipe.too_large_pattern: "Fehler in der Datei - Das geformte Rezept '' hat ein Muster mit mehr als 3 Zeilen oder Spalten." +warning.config.recipe.mismatched_shaped_pattern: "Fehler in der Datei - Das geformte Rezept '' hat ein fehlerhaftes Muster und Zutaten." +warning.config.recipe.mismatched_shulker_box: "Fehler in der Datei - Das Shulker-Box-Rezept '' hat ein fehlerhaftes Muster und Zutaten." +warning.config.recipe.mismatched_unshaped_pattern: "Fehler in der Datei - Das ungeformte Rezept '' hat ein fehlerhaftes Muster und Zutaten." +warning.config.recipe.missing_category: "Fehler in der Datei - Dem Rezept '' fehlt das erforderliche 'category'-Argument." +warning.config.recipe.missing_experience: "Fehler in der Datei - Dem Kochrezept '' fehlt das erforderliche 'experience'-Argument." +warning.config.recipe.missing_cooking_time: "Fehler in der Datei - Dem Kochrezept '' fehlt das erforderliche 'cooking-time'-Argument." +warning.config.recipe.missing_group: "Fehler in der Datei - Dem Rezept '' fehlt das erforderliche 'group'-Argument." +warning.config.recipe.missing_book: "Fehler in der Datei - Dem Rezept '' fehlt das erforderliche 'book'-Argument." +warning.config.loot_table.duplicate: "Fehler in der Datei - Doppelte Loot-Tabelle ''. Bitte prüfen Sie, ob in anderen Dateien die gleiche Konfiguration vorhanden ist." +warning.config.loot_table.missing_type: "Fehler in der Datei - Der Loot-Tabelle '' fehlt das erforderliche 'type'-Argument." +warning.config.loot_table.invalid_type: "Fehler in der Datei - Die Loot-Tabelle '' verwendet einen ungültigen Loot-Tabellen-Typ ''." +warning.config.loot_table.missing_rolls: "Fehler in der Datei - Der Loot-Tabelle '' fehlt das erforderliche 'rolls'-Argument." +warning.config.loot_table.missing_entries: "Fehler in der Datei - Der Loot-Tabelle '' fehlt das erforderliche 'entries'-Argument." +warning.config.loot_table.missing_entry_type: "Fehler in der Datei - Einer der Loot-Tabellen-Einträge in '' hat kein erforderliches 'type'-Argument." +warning.config.loot_table.invalid_entry_type: "Fehler in der Datei - Einer der Loot-Tabellen-Einträge in '' verwendet einen ungültigen Typ ''." +warning.config.loot_table.missing_entry_name: "Fehler in der Datei - Einer der Loot-Tabellen-Einträge in '' hat kein erforderliches 'name'-Argument." +warning.config.loot_table.missing_entry_weight: "Fehler in der Datei - Einer der Loot-Tabellen-Einträge in '' hat kein erforderliches 'weight'-Argument." +warning.config.loot_table.missing_function_type: "Fehler in der Datei - Eine der Loot-Tabellen-Funktionen in '' hat kein erforderliches 'type'-Argument." +warning.config.loot_table.invalid_function_type: "Fehler in der Datei - Eine der Loot-Tabellen-Funktionen in '' verwendet einen ungültigen Typ ''." +warning.config.loot_table.missing_condition_type: "Fehler in der Datei - Eine der Loot-Tabellen-Bedingungen in '' hat kein erforderliches 'type'-Argument." +warning.config.loot_table.invalid_condition_type: "Fehler in der Datei - Eine der Loot-Tabellen-Bedingungen in '' verwendet einen ungültigen Typ ''." +warning.config.resource_pack.generation.missing_equipment_texture: "Ausrüstung '' hat keine Textur ''" +warning.config.equipment.duplicate: "Problem in der Datei gefunden – Duplizierte Ausrüstung ''. Bitte prüfe, ob es dieselbe Konfiguration in anderen Dateien gibt." +warning.config.equipment.missing_type: "Problem in der Datei gefunden – Der Ausrüstung '' fehlt das erforderliche Argument 'type'." +warning.config.equipment.invalid_type: "Problem in der Datei gefunden – Die Ausrüstung '' verwendet ein ungültiges Argument 'type'." +warning.config.equipment.invalid_sacrificed_armor: "Problem in config.yml bei 'equipment.sacrificed-vanilla-armor' gefunden – Ungültiger Vanille-Rüstungstyp ''." \ No newline at end of file From afa7920b5ff07ca73d258d689cb50e8a44bf53a3 Mon Sep 17 00:00:00 2001 From: tamashii Date: Sat, 2 Aug 2025 23:27:20 +0200 Subject: [PATCH 73/83] A german translatsion update. --- .../src/main/resources/translations/de.yml | 146 +++++++++--------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 9b16042f2..8f505365b 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -49,11 +49,11 @@ command.item.get.failure.not_exist: "':'':''>" command.item.give.success.multiple: "':'':''>" command.item.give.failure.not_exist: "'>" -command.search_recipe.not_found: "Kein Rezept für diesen Gegenstand gefunden" -command.search_usage.not_found: "Keine Verwendung für diesen Gegenstand gefunden" -command.search_recipe.no_item: "Bitte halten Sie einen Gegenstand, bevor Sie diesen Befehl ausführen" -command.search_usage.no_item: "Bitte halten Sie einen Gegenstand, bevor Sie diesen Befehl ausführen" -command.totem_animation.failure.not_totem: "Gegenstand '' ist kein minecraft:totem_of_undying" +command.search_recipe.not_found: "Kein Rezept für diesen Item gefunden" +command.search_usage.not_found: "Keine Verwendung für dieses Item gefunden" +command.search_recipe.no_item: "Bitte halten Sie ein Item, bevor Sie diesen Befehl ausführen" +command.search_usage.no_item: "Bitte halten Sie ein Item, bevor Sie diesen Befehl ausführen" +command.totem_animation.failure.not_totem: "Item '' ist kein minecraft:totem_of_undying" command.resource.enable.success: "Ressource aktiviert. Führen Sie /ce reload all aus, um die Änderungen anzuwenden" command.resource.enable.failure.unknown: "Unbekannte Ressource " command.resource.disable.success: "Ressource deaktiviert. Führen Sie /ce reload all aus, um die Änderungen anzuwenden" @@ -155,72 +155,72 @@ warning.config.furniture.element.missing_item: "Problem in Datei warning.config.furniture.settings.unknown: "Problem in Datei gefunden - Das Möbelstück '' verwendet einen unbekannten Einstellungstyp ''." warning.config.furniture.hitbox.invalid_type: "Problem in Datei gefunden - Das Möbelstück '' verwendet einen ungültigen Hitbox-Typ ''." warning.config.furniture.hitbox.custom.invalid_entity: "Problem in Datei gefunden - Das Möbelstück '' verwendet eine benutzerdefinierte Hitbox mit ungültigem Entitätstyp ''." -warning.config.item.duplicate: "Problem in Datei gefunden - Duplizierter Gegenstand ''. Bitte überprüfen Sie, ob dieselbe Konfiguration in anderen Dateien vorhanden ist." -warning.config.item.settings.unknown: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen unbekannten Einstellungstyp ''." -warning.config.item.settings.invulnerable.invalid_damage_source: "Problem in Datei gefunden - Der Gegenstand '' verwendet eine unbekannte Schadensquelle ''. Erlaubte Quellen: []." -warning.config.item.settings.equippable.missing_slot: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'slot'-Argument für die 'equippable'-Einstellung." -warning.config.item.missing_material: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'material'-Argument." -warning.config.item.invalid_material: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen Materialtyp ''." -warning.config.item.invalid_custom_model_data: "Problem in Datei gefunden - Der Gegenstand '' verwendet negative benutzerdefinierte Modelldaten '', die ungültig sind." -warning.config.item.bad_custom_model_data: "Problem in Datei gefunden - Der Gegenstand '' verwendet benutzerdefinierte Modelldaten '', die zu groß sind. Es wird empfohlen, einen Wert unter 16.777.216 zu verwenden." -warning.config.item.custom_model_data_conflict: "Problem in Datei gefunden - Der Gegenstand '' verwendet benutzerdefinierte Modelldaten '', die bereits von Gegenstand '' belegt sind." -warning.config.item.invalid_component: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen nicht existierenden Komponententyp ''." -warning.config.item.missing_model_id: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'custom-model-data' oder 'item-model'-Argument." -warning.config.item.missing_model: "Problem in Datei gefunden - Dem Gegenstand '' fehlt der erforderliche 'model'-Abschnitt für die Unterstützung von 1.21.4+-Ressourcenpaketen." -warning.config.item.behavior.missing_type: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'type'-Argument für sein Gegenstandsverhalten." -warning.config.item.behavior.invalid_type: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen Gegenstandsverhaltenstyp ''." -warning.config.item.behavior.block.missing_block: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'block'-Argument für das 'block_item'-Verhalten." -warning.config.item.behavior.furniture.missing_furniture: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'furniture'-Argument für das 'furniture_item'-Verhalten." -warning.config.item.behavior.liquid_collision.missing_block: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'block'-Argument für das 'liquid_collision_block_item'-Verhalten." -warning.config.item.legacy_model.missing_path: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'path'-Argument für das Legacy-Modell." -warning.config.item.legacy_model.overrides.missing_path: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'path'-Argument für Legacy-Modell-Überschreibungen." -warning.config.item.legacy_model.overrides.missing_predicate: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'predicate'-Argument für Legacy-Modell-Überschreibungen." -warning.config.item.legacy_model.cannot_convert: "Problem in Datei gefunden - Kann 1.21.4+-Gegenstände für Gegenstand '' nicht in das Legacy-Format konvertieren. Bitte erstellen Sie den Abschnitt 'legacy-model' für diesen Gegenstand manuell." -warning.config.item.model.invalid_type: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen Modelltyp ''." -warning.config.item.model.tint.missing_type: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'type'-Argument für die Tönung." -warning.config.item.model.tint.invalid_type: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen Tönungstyp ''." -warning.config.item.model.tint.constant.missing_value: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'value'-Argument für die konstante Tönung." -warning.config.item.model.tint.grass.invalid_temp: "Problem in Datei gefunden - Der Gegenstand '' verwendet eine ungültige Temperatur '' für die Grastönung, die zwischen 0 und 1 liegen sollte." -warning.config.item.model.tint.grass.invalid_downfall: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen Niederschlag '' für die Grastönung, der zwischen 0 und 1 liegen sollte." -warning.config.item.model.tint.invalid_value: "Problem in Datei gefunden - Der Gegenstand '' verwendet eine ungültige Tönung ''." -warning.config.item.model.base.missing_path: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'path'-Argument für das Modell 'minecraft:model'." -warning.config.item.model.base.invalid_path: "Problem in Datei gefunden - Der Gegenstand '' hat ein ungültiges 'path'-Argument '' für das Modell 'minecraft:model', das illegale Zeichen enthält. Bitte lesen Sie https://minecraft.wiki/w/Resource_location#Legal_characters." -warning.config.item.model.condition.missing_property: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'property'-Argument für das Modell 'minecraft:condition'." -warning.config.item.model.condition.invalid_property: "Problem in Datei gefunden - Der Gegenstand '' verwendet eine ungültige Eigenschaft '' für das Modell 'minecraft:condition'." -warning.config.item.model.condition.missing_on_true: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'on-true'-Argument für das Modell 'minecraft:condition'." -warning.config.item.model.condition.missing_on_false: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'on-false'-Argument für das Modell 'minecraft:condition'." -warning.config.item.model.condition.keybind.missing_keybind: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'keybind'-Argument für die Eigenschaft 'minecraft:keybind_down'." -warning.config.item.model.condition.component.missing_predicate: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'predicate'-Argument für die Eigenschaft 'minecraft:has_component'." -warning.config.item.model.condition.component.missing_value: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'value'-Argument für die Eigenschaft 'minecraft:has_component'." -warning.config.item.model.condition.has_component.missing_component: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'component'-Argument für die Eigenschaft 'minecraft:has_component'." -warning.config.item.model.composite.missing_models: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'models'-Argument für das Modell 'minecraft:composite'." -warning.config.item.model.range_dispatch.missing_property: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'property'-Argument für das Modell 'minecraft:range_dispatch'." -warning.config.item.model.range_dispatch.invalid_property: "Problem in Datei gefunden - Der Gegenstand '' verwendet eine ungültige Eigenschaft '' für das Modell 'minecraft:range_dispatch'." -warning.config.item.model.range_dispatch.missing_entries: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'entries'-Argument für das Modell 'minecraft:composite'." -warning.config.item.model.range_dispatch.entry.missing_model: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'model'-Argument für einen der Einträge im Modell 'minecraft:composite'." -warning.config.item.model.range_dispatch.compass.missing_target: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'target'-Argument für die Eigenschaft 'minecraft:compass'." -warning.config.item.model.range_dispatch.time.missing_source: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'source'-Argument für die Eigenschaft 'minecraft:time'." -warning.config.item.model.select.missing_property: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'property'-Argument für das Modell 'minecraft:select'." -warning.config.item.model.select.invalid_property: "Problem in Datei gefunden - Der Gegenstand '' verwendet eine ungültige Eigenschaft '' für das Modell 'minecraft:select'." -warning.config.item.model.select.missing_cases: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'cases'-Argument für das Modell 'minecraft:select'." -warning.config.item.model.select.case.missing_when: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'when'-Argument für einen der Fälle im Modell 'minecraft:select'." -warning.config.item.model.select.case.missing_model: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'model'-Argument für einen der Fälle im Modell 'minecraft:select'." -warning.config.item.model.select.component.missing_component: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'component'-Argument für die Eigenschaft 'minecraft:component'." -warning.config.item.model.select.block_state.missing_property: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'block-state-property'-Argument für die Eigenschaft 'minecraft:block_state'." -warning.config.item.model.select.local_time.missing_pattern: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'pattern'-Argument für die Eigenschaft 'minecraft:local_time'." -warning.config.item.model.special.missing_type: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'type'-Argument für das Modell 'minecraft:special'." -warning.config.item.model.special.missing_path: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'path'-Argument für das Modell 'minecraft:special'." -warning.config.item.model.special.invalid_path: "Problem in Datei gefunden - Der Gegenstand '' hat ein ungültiges 'path'-Argument '' für das Modell 'minecraft:special', das illegale Zeichen enthält. Bitte lesen Sie https://minecraft.wiki/w/Resource_location#Legal_characters." -warning.config.item.model.special.invalid_type: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen Typ '' für das Modell 'minecraft:special'." -warning.config.item.model.special.banner.missing_color: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'color'-Argument für das Spezialmodell 'minecraft:banner'." -warning.config.item.model.special.bed.missing_texture: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:bed'." -warning.config.item.model.special.sign.missing_wood_type: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'wood-type'-Argument für das Spezialmodell 'minecraft:hanging_sign'/'minecraft:standing_sign'." -warning.config.item.model.special.sign.missing_texture: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:hanging_sign'/'minecraft:standing_sign'." -warning.config.item.model.special.chest.missing_texture: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:chest'." -warning.config.item.model.special.chest.invalid_openness: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen 'openness'-Wert '' für das Spezialmodell 'minecraft:chest'. Gültiger Bereich '0~1.'" -warning.config.item.model.special.shulker_box.missing_texture: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:shulker_box'." -warning.config.item.model.special.shulker_box.invalid_openness: "Problem in Datei gefunden - Der Gegenstand '' verwendet einen ungültigen 'openness'-Wert '' für das Spezialmodell 'minecraft:shulker_box'. Gültiger Bereich '0~1.'" -warning.config.item.model.special.head.missing_kind: "Problem in Datei gefunden - Dem Gegenstand '' fehlt das erforderliche 'kind'-Argument für das Spezialmodell 'minecraft:head'." +warning.config.item.duplicate: "Problem in Datei gefunden - Dupliziertes Item ''. Bitte überprüfen Sie, ob dieselbe Konfiguration in anderen Dateien vorhanden ist." +warning.config.item.settings.unknown: "Problem in Datei gefunden - Das Item '' verwendet einen unbekannten Einstellungstyp ''." +warning.config.item.settings.invulnerable.invalid_damage_source: "Problem in Datei gefunden - Das Item '' verwendet eine unbekannte Schadensquelle ''. Erlaubte Quellen: []." +warning.config.item.settings.equippable.missing_slot: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'slot'-Argument für die 'equippable'-Einstellung." +warning.config.item.missing_material: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'material'-Argument." +warning.config.item.invalid_material: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen Materialtyp ''." +warning.config.item.invalid_custom_model_data: "Problem in Datei gefunden - Das Item '' verwendet negative benutzerdefinierte Modelldaten '', die ungültig sind." +warning.config.item.bad_custom_model_data: "Problem in Datei gefunden - Das Item '' verwendet benutzerdefinierte Modelldaten '', die zu groß sind. Es wird empfohlen, einen Wert unter 16.777.216 zu verwenden." +warning.config.item.custom_model_data_conflict: "Problem in Datei gefunden - Das Item '' verwendet benutzerdefinierte Modelldaten '', die bereits von Item '' belegt sind." +warning.config.item.invalid_component: "Problem in Datei gefunden - Das Item '' verwendet einen nicht existierenden Komponententyp ''." +warning.config.item.missing_model_id: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'custom-model-data' oder 'item-model'-Argument." +warning.config.item.missing_model: "Problem in Datei gefunden - Das Item '' fehlt der erforderliche 'model'-Abschnitt für die Unterstützung von 1.21.4+-Ressourcenpaketen." +warning.config.item.behavior.missing_type: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'type'-Argument für sein Itemsverhalten." +warning.config.item.behavior.invalid_type: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen Itemsverhaltenstyp ''." +warning.config.item.behavior.block.missing_block: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'block'-Argument für das 'block_item'-Verhalten." +warning.config.item.behavior.furniture.missing_furniture: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'furniture'-Argument für das 'furniture_item'-Verhalten." +warning.config.item.behavior.liquid_collision.missing_block: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'block'-Argument für das 'liquid_collision_block_item'-Verhalten." +warning.config.item.legacy_model.missing_path: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'path'-Argument für das Legacy-Modell." +warning.config.item.legacy_model.overrides.missing_path: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'path'-Argument für Legacy-Modell-Überschreibungen." +warning.config.item.legacy_model.overrides.missing_predicate: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'predicate'-Argument für Legacy-Modell-Überschreibungen." +warning.config.item.legacy_model.cannot_convert: "Problem in Datei gefunden - Kann 1.21.4+-Gegenstände für Item '' nicht in das Legacy-Format konvertieren. Bitte erstellen Sie den Abschnitt 'legacy-model' für diesen Item manuell." +warning.config.item.model.invalid_type: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen Modelltyp ''." +warning.config.item.model.tint.missing_type: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'type'-Argument für die Tönung." +warning.config.item.model.tint.invalid_type: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen Tönungstyp ''." +warning.config.item.model.tint.constant.missing_value: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'value'-Argument für die konstante Tönung." +warning.config.item.model.tint.grass.invalid_temp: "Problem in Datei gefunden - Das Item '' verwendet eine ungültige Temperatur '' für die Grastönung, die zwischen 0 und 1 liegen sollte." +warning.config.item.model.tint.grass.invalid_downfall: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen Niederschlag '' für die Grastönung, der zwischen 0 und 1 liegen sollte." +warning.config.item.model.tint.invalid_value: "Problem in Datei gefunden - Das Item '' verwendet eine ungültige Tönung ''." +warning.config.item.model.base.missing_path: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'path'-Argument für das Modell 'minecraft:model'." +warning.config.item.model.base.invalid_path: "Problem in Datei gefunden - Das Item '' hat ein ungültiges 'path'-Argument '' für das Modell 'minecraft:model', das illegale Zeichen enthält. Bitte lesen Sie https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.item.model.condition.missing_property: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'property'-Argument für das Modell 'minecraft:condition'." +warning.config.item.model.condition.invalid_property: "Problem in Datei gefunden - Das Item '' verwendet eine ungültige Eigenschaft '' für das Modell 'minecraft:condition'." +warning.config.item.model.condition.missing_on_true: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'on-true'-Argument für das Modell 'minecraft:condition'." +warning.config.item.model.condition.missing_on_false: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'on-false'-Argument für das Modell 'minecraft:condition'." +warning.config.item.model.condition.keybind.missing_keybind: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'keybind'-Argument für die Eigenschaft 'minecraft:keybind_down'." +warning.config.item.model.condition.component.missing_predicate: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'predicate'-Argument für die Eigenschaft 'minecraft:has_component'." +warning.config.item.model.condition.component.missing_value: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'value'-Argument für die Eigenschaft 'minecraft:has_component'." +warning.config.item.model.condition.has_component.missing_component: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'component'-Argument für die Eigenschaft 'minecraft:has_component'." +warning.config.item.model.composite.missing_models: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'models'-Argument für das Modell 'minecraft:composite'." +warning.config.item.model.range_dispatch.missing_property: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'property'-Argument für das Modell 'minecraft:range_dispatch'." +warning.config.item.model.range_dispatch.invalid_property: "Problem in Datei gefunden - Das Item '' verwendet eine ungültige Eigenschaft '' für das Modell 'minecraft:range_dispatch'." +warning.config.item.model.range_dispatch.missing_entries: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'entries'-Argument für das Modell 'minecraft:composite'." +warning.config.item.model.range_dispatch.entry.missing_model: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'model'-Argument für einen der Einträge im Modell 'minecraft:composite'." +warning.config.item.model.range_dispatch.compass.missing_target: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'target'-Argument für die Eigenschaft 'minecraft:compass'." +warning.config.item.model.range_dispatch.time.missing_source: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'source'-Argument für die Eigenschaft 'minecraft:time'." +warning.config.item.model.select.missing_property: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'property'-Argument für das Modell 'minecraft:select'." +warning.config.item.model.select.invalid_property: "Problem in Datei gefunden - Das Item '' verwendet eine ungültige Eigenschaft '' für das Modell 'minecraft:select'." +warning.config.item.model.select.missing_cases: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'cases'-Argument für das Modell 'minecraft:select'." +warning.config.item.model.select.case.missing_when: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'when'-Argument für einen der Fälle im Modell 'minecraft:select'." +warning.config.item.model.select.case.missing_model: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'model'-Argument für einen der Fälle im Modell 'minecraft:select'." +warning.config.item.model.select.component.missing_component: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'component'-Argument für die Eigenschaft 'minecraft:component'." +warning.config.item.model.select.block_state.missing_property: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'block-state-property'-Argument für die Eigenschaft 'minecraft:block_state'." +warning.config.item.model.select.local_time.missing_pattern: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'pattern'-Argument für die Eigenschaft 'minecraft:local_time'." +warning.config.item.model.special.missing_type: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'type'-Argument für das Modell 'minecraft:special'." +warning.config.item.model.special.missing_path: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'path'-Argument für das Modell 'minecraft:special'." +warning.config.item.model.special.invalid_path: "Problem in Datei gefunden - Das Item '' hat ein ungültiges 'path'-Argument '' für das Modell 'minecraft:special', das illegale Zeichen enthält. Bitte lesen Sie https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.item.model.special.invalid_type: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen Typ '' für das Modell 'minecraft:special'." +warning.config.item.model.special.banner.missing_color: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'color'-Argument für das Spezialmodell 'minecraft:banner'." +warning.config.item.model.special.bed.missing_texture: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:bed'." +warning.config.item.model.special.sign.missing_wood_type: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'wood-type'-Argument für das Spezialmodell 'minecraft:hanging_sign'/'minecraft:standing_sign'." +warning.config.item.model.special.sign.missing_texture: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:hanging_sign'/'minecraft:standing_sign'." +warning.config.item.model.special.chest.missing_texture: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:chest'." +warning.config.item.model.special.chest.invalid_openness: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen 'openness'-Wert '' für das Spezialmodell 'minecraft:chest'. Gültiger Bereich '0~1.'" +warning.config.item.model.special.shulker_box.missing_texture: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'texture'-Argument für das Spezialmodell 'minecraft:shulker_box'." +warning.config.item.model.special.shulker_box.invalid_openness: "Problem in Datei gefunden - Das Item '' verwendet einen ungültigen 'openness'-Wert '' für das Spezialmodell 'minecraft:shulker_box'. Gültiger Bereich '0~1.'" +warning.config.item.model.special.head.missing_kind: "Problem in Datei gefunden - Das Item '' fehlt das erforderliche 'kind'-Argument für das Spezialmodell 'minecraft:head'." warning.config.block.duplicate: "Problem in Datei gefunden - Duplizierter Block ''. Bitte überprüfen Sie, ob dieselbe Konfiguration in anderen Dateien vorhanden ist." warning.config.block.missing_state: "Problem in Datei gefunden - Dem Block '' fehlt das erforderliche 'state'-Argument." warning.config.block.state.property.missing_type: "Problem in Datei gefunden - Dem Block '' fehlt das erforderliche 'type'-Argument für die Eigenschaft ''." @@ -379,11 +379,11 @@ warning.config.function.remove_cooldown.missing_id: "Problem in Datei Problem in Datei gefunden - Der Konfiguration '' fehlt das erforderliche 'type'-Argument für den Selektor." warning.config.selector.invalid_type: "Problem in Datei gefunden - Die Konfiguration '' verwendet einen ungültigen Selektortyp ''." warning.config.selector.invalid_target: "Problem in Datei gefunden - Die Konfiguration '' verwendet ein ungültiges Selektorziel ''." -warning.config.resource_pack.item_model.already_exist: "Fehler beim Generieren des Gegenstandsmodells für '' da die Datei '' bereits existiert." +warning.config.resource_pack.item_model.already_exist: "Fehler beim Generieren des Itemsmodells für '' da die Datei '' bereits existiert." warning.config.resource_pack.model.generation.already_exist: "Fehler beim Generieren des Modells, da die Modelldatei '' bereits existiert." warning.config.resource_pack.generation.missing_font_texture: "Schriftart '' fehlt die erforderliche Textur: ''" warning.config.resource_pack.generation.missing_model_texture: "Modell '' fehlt Textur ''" -warning.config.resource_pack.generation.missing_item_model: "Gegenstand '' fehlt Modelldatei: ''" +warning.config.resource_pack.generation.missing_item_model: "Item '' fehlt Modelldatei: ''" warning.config.resource_pack.generation.missing_block_model: "Block '' fehlt Modelldatei: ''" warning.config.resource_pack.generation.missing_parent_model: "Modell '' kann das Elternmodell nicht finden: ''" warning.config.resource_pack.generation.malformatted_json: "Json-Datei '' ist fehlerhaft formatiert." From 44e2f234dea11e6c19c05b3c5578e09c269b0f2e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 3 Aug 2025 21:07:43 +0800 Subject: [PATCH 74/83] =?UTF-8?q?=E9=85=8D=E6=96=B9=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitCustomItem.java | 13 +- .../bukkit/item/BukkitItemManager.java | 44 +- .../bukkit/item/CloneableConstantItem.java | 32 - .../item/factory/BukkitItemFactory.java | 14 +- .../factory/ComponentItemFactory1_20_5.java | 5 - .../item/factory/UniversalItemFactory.java | 5 - .../item/recipe/BukkitRecipeManager.java | 1259 +++++------------ .../item/recipe/CrafterEventListener.java | 82 -- .../item/recipe/RecipeEventListener.java | 339 +---- .../bukkit/pack/BukkitPackManager.java | 16 - .../plugin/injector/RecipeInjector.java | 252 +--- .../plugin/network/BukkitNetworkManager.java | 2 +- .../reflection/minecraft/CoreReflections.java | 4 - .../plugin/user/BukkitServerPlayer.java | 10 - .../bukkit/util/InteractUtils.java | 8 +- .../bukkit/util/ItemStackUtils.java | 10 +- .../craftengine/bukkit/util/RecipeUtils.java | 43 - .../bukkit/world/BukkitWorldManager.java | 7 - .../src/main/resources/translations/en.yml | 2 + .../craftengine/core/block/BlockSettings.java | 2 +- .../core/item/AbstractCustomItem.java | 9 +- .../core/item/AbstractItemManager.java | 45 +- .../core/item/CloneableConstantItem.java | 30 + .../craftengine/core/item/CustomItem.java | 4 + .../craftengine/core/item/Item.java | 4 + .../craftengine/core/item/ItemManager.java | 18 +- .../item/recipe/AbstractGroupedRecipe.java | 2 +- .../item/recipe/AbstractRecipeFactory.java | 58 - .../item/recipe/AbstractRecipeManager.java | 38 +- .../item/recipe/AbstractRecipeSerializer.java | 119 ++ .../item/recipe/CustomBlastingRecipe.java | 34 +- .../core/item/recipe/CustomBrewingRecipe.java | 12 +- .../item/recipe/CustomCampfireRecipe.java | 34 +- .../core/item/recipe/CustomCookingRecipe.java | 2 +- .../recipe/CustomCraftingTableRecipe.java | 2 +- .../core/item/recipe/CustomRecipeResult.java | 24 +- .../core/item/recipe/CustomShapedRecipe.java | 44 +- .../item/recipe/CustomShapelessRecipe.java | 69 +- .../item/recipe/CustomSmeltingRecipe.java | 34 +- .../recipe/CustomSmithingTransformRecipe.java | 37 +- .../item/recipe/CustomSmithingTrimRecipe.java | 45 +- .../core/item/recipe/CustomSmokingRecipe.java | 34 +- .../item/recipe/CustomStoneCuttingRecipe.java | 22 +- .../item/recipe/DatapackRecipeResult.java | 10 + .../core/item/recipe/Ingredient.java | 23 +- .../craftengine/core/item/recipe/Recipe.java | 4 + .../core/item/recipe/RecipeFactory.java | 46 - .../core/item/recipe/RecipeSerializer.java | 13 + .../core/item/recipe/RecipeSerializers.java | 35 +- .../core/item/recipe/UniqueIdItem.java | 10 +- .../core/item/recipe/input/SmithingInput.java | 9 +- .../reader/VanillaRecipeReader1_20.java | 148 ++ .../reader/VanillaRecipeReader1_20_5.java | 34 + .../reader/VanillaRecipeReader1_21_2.java | 8 +- .../item/recipe/vanilla/RecipeResult.java | 10 - .../recipe/vanilla/VanillaBlastingRecipe.java | 3 +- .../recipe/vanilla/VanillaCampfireRecipe.java | 3 +- .../recipe/vanilla/VanillaCookingRecipe.java | 3 +- .../recipe/vanilla/VanillaCraftingRecipe.java | 3 +- .../recipe/vanilla/VanillaGroupedRecipe.java | 8 +- .../recipe/vanilla/VanillaRecipeReader.java | 41 +- .../recipe/vanilla/VanillaShapedRecipe.java | 3 +- .../vanilla/VanillaShapelessRecipe.java | 3 +- .../recipe/vanilla/VanillaSmeltingRecipe.java | 3 +- .../VanillaSmithingTransformRecipe.java | 7 +- .../recipe/vanilla/VanillaSmokingRecipe.java | 3 +- .../vanilla/VanillaStoneCuttingRecipe.java | 3 +- .../vanilla/reader/AbstractRecipeReader.java | 48 - .../reader/VanillaRecipeReader1_20.java | 206 --- .../reader/VanillaRecipeReader1_20_5.java | 34 - .../reader/VanillaRecipeReader1_21_5.java | 17 - .../core/registry/BuiltInRegistries.java | 5 +- .../craftengine/core/registry/Registries.java | 5 +- gradle.properties | 4 +- 74 files changed, 1227 insertions(+), 2394 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/CloneableConstantItem.java delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/DatapackRecipeResult.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializer.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20_5.java rename core/src/main/java/net/momirealms/craftengine/core/item/recipe/{vanilla => }/reader/VanillaRecipeReader1_21_2.java (86%) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/RecipeResult.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/AbstractRecipeReader.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20_5.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_5.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index 4f8e68a97..5bd11d54c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -21,12 +21,12 @@ public class BukkitCustomItem extends AbstractCustomItem { private final Object item; private final Object clientItem; - public BukkitCustomItem(UniqueKey id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey, + public BukkitCustomItem(boolean isVanillaItem, UniqueKey id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey, List behaviors, List> modifiers, List> clientBoundModifiers, ItemSettings settings, Map>> events) { - super(id, materialKey, clientBoundMaterialKey, behaviors, modifiers, clientBoundModifiers, settings, events); + super(isVanillaItem, id, materialKey, clientBoundMaterialKey, behaviors, modifiers, clientBoundModifiers, settings, events); this.item = item; this.clientItem = clientItem; } @@ -64,6 +64,7 @@ public class BukkitCustomItem extends AbstractCustomItem { } public static class BuilderImpl implements Builder { + private boolean isVanillaItem; private UniqueKey id; private Key itemKey; private final Object item; @@ -80,6 +81,12 @@ public class BukkitCustomItem extends AbstractCustomItem { this.clientBoundItem = clientBoundItem; } + @Override + public Builder isVanillaItem(boolean is) { + this.isVanillaItem = is; + return this; + } + @Override public Builder id(UniqueKey id) { this.id = id; @@ -150,7 +157,7 @@ public class BukkitCustomItem extends AbstractCustomItem { public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); this.clientBoundModifiers.addAll(this.settings.clientBoundModifiers()); - return new BukkitCustomItem(this.id, this.item, this.clientBoundItem, this.itemKey, this.clientBoundItemKey, List.copyOf(this.behaviors), + return new BukkitCustomItem(this.isVanillaItem, this.id, this.item, this.clientBoundItem, this.itemKey, this.clientBoundItemKey, List.copyOf(this.behaviors), List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events); } } 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 9a060037f..219e20ef5 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 @@ -17,7 +17,7 @@ import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.modifier.IdModifier; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.plugin.config.Config; @@ -70,10 +70,9 @@ public class BukkitItemManager extends AbstractItemManager { this.bedrockItemHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(Key.of("minecraft:bedrock")))).get(); this.registerCustomTrimMaterial(); this.loadLastRegisteredPatterns(); - ItemStack emptyStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.instance$ItemStack$EMPTY); - this.emptyItem = this.wrap(emptyStack); - this.emptyUniqueItem = new UniqueIdItem<>(UniqueKey.AIR, this.emptyItem); + this.emptyItem = this.factory.wrap(emptyStack); + this.emptyUniqueItem = UniqueIdItem.of(this.emptyItem); this.decoratedHashOpsGenerator = VersionHelper.isOrAbove1_21_5() ? (Function) FastNMS.INSTANCE.createDecoratedHashOpsGenerator(MRegistryOps.HASHCODE) : null; } @@ -158,13 +157,33 @@ public class BukkitItemManager extends AbstractItemManager { } } + @Override + public Item build(DatapackRecipeResult result) { + if (result.components() == null) { + ItemStack itemStack = createVanillaItemStack(Key.of(result.id())); + return wrap(itemStack).count(result.count()); + } else { + // 低版本无法应用nbt或组件,所以这里是1.20.5+ + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("id", result.id()); + jsonObject.addProperty("count", result.count()); + jsonObject.add("components", result.components()); + Object nmsStack = CoreReflections.instance$ItemStack$CODEC.parse(MRegistryOps.JSON, jsonObject) + .resultOrPartial((itemId) -> plugin.logger().severe("Tried to load invalid item: '" + itemId + "'")).orElse(null); + if (nmsStack == null) { + return this.emptyItem; + } + return wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsStack)); + } + } + @Override public Optional> getVanillaItem(Key key) { ItemStack vanilla = createVanillaItemStack(key); if (vanilla == null) { return Optional.empty(); } - return Optional.of(new CloneableConstantItem(key, this.wrap(vanilla))); + return Optional.of(CloneableConstantItem.of(this.wrap(vanilla))); } @Override @@ -356,23 +375,10 @@ public class BukkitItemManager extends AbstractItemManager { @Override public @NotNull Item wrap(ItemStack itemStack) { - if (itemStack == null) return this.emptyItem; + if (itemStack == null || itemStack.isEmpty()) return this.emptyItem; return this.factory.wrap(itemStack); } - @Override - public Key itemId(ItemStack itemStack) { - Item wrapped = wrap(itemStack); - return wrapped.id(); - } - - @Override - public Key customItemId(ItemStack itemStack) { - Item wrapped = wrap(itemStack); - if (!wrapped.hasTag(IdModifier.CRAFT_ENGINE_ID)) return null; - return wrapped.id(); - } - @Override protected CustomItem.Builder createPlatformItemBuilder(UniqueKey id, Key materialId, Key clientBoundMaterialId) { Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(materialId)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/CloneableConstantItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/CloneableConstantItem.java deleted file mode 100644 index 13fb185c6..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/CloneableConstantItem.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.momirealms.craftengine.bukkit.item; - -import net.momirealms.craftengine.core.item.BuildableItem; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.util.Key; -import org.bukkit.inventory.ItemStack; - -public class CloneableConstantItem implements BuildableItem { - private final Item item; - private final Key id; - - public CloneableConstantItem(Key id, Item item) { - this.item = item; - this.id = id; - } - - @Override - public Key id() { - return this.id; - } - - @Override - public Item buildItem(ItemBuildContext context, int count) { - return this.item.copyWithCount(count); - } - - @Override - public ItemStack buildItemStack(ItemBuildContext context, int count) { - return this.item.copyWithCount(count).getItem(); - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 7b2ded9df..b042fe12c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.ExternalItemSource; import net.momirealms.craftengine.core.item.ItemFactory; -import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.setting.EquipmentData; @@ -66,6 +65,11 @@ public abstract class BukkitItemFactory> extend } } + @Override + protected boolean isEmpty(W item) { + return FastNMS.INSTANCE.method$ItemStack$isEmpty(item.getLiteralObject()); + } + @SuppressWarnings("deprecation") @Override protected byte[] toByteArray(W item) { @@ -80,12 +84,15 @@ public abstract class BukkitItemFactory> extend @Override protected Key vanillaId(W item) { Object i = FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()); - if (i == null) return ItemKeys.AIR; + if (i == null) return null; return KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, i)); } @Override protected Key id(W item) { + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(item.getLiteralObject())) { + return null; + } return customId(item).orElse(vanillaId(item)); } @@ -96,6 +103,9 @@ public abstract class BukkitItemFactory> extend @Override protected UniqueKey recipeIngredientID(W item) { + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(item.getLiteralObject())) { + return null; + } if (this.hasExternalRecipeSource) { for (ExternalItemSource source : this.recipeIngredientSources) { String id = source.id(item.getItem()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 21f37ec25..d5552f058 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -31,11 +31,6 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory { return item.remove(path); } - @Override - protected boolean isEmpty(LegacyItemWrapper item) { - return item.getItem().isEmpty(); - } - @Override protected Optional customId(LegacyItemWrapper item) { Object id = item.getJavaTag(IdModifier.CRAFT_ENGINE_ID); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index b0af3b91c..7ec945e9c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -6,7 +6,6 @@ import io.papermc.paper.potion.PotionMix; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; -import net.momirealms.craftengine.bukkit.item.CloneableConstantItem; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.RecipeInjector; @@ -14,795 +13,211 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitExcepti 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.MRegistries; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; import net.momirealms.craftengine.bukkit.util.KeyUtils; -import net.momirealms.craftengine.bukkit.util.MaterialUtils; -import net.momirealms.craftengine.bukkit.util.RecipeUtils; -import net.momirealms.craftengine.core.item.*; +import net.momirealms.craftengine.core.item.BuildableItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.recipe.*; -import net.momirealms.craftengine.core.item.recipe.Recipe; -import net.momirealms.craftengine.core.item.recipe.vanilla.*; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.event.HandlerList; -import org.bukkit.inventory.*; -import org.bukkit.inventory.recipe.CookingBookCategory; -import org.bukkit.inventory.recipe.CraftingBookCategory; +import org.bukkit.inventory.ItemStack; +import java.io.IOException; import java.io.Reader; import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; +import java.sql.Ref; import java.util.*; -import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; +// todo 在folia上替换recipe map使其线程安全 public class BukkitRecipeManager extends AbstractRecipeManager { private static BukkitRecipeManager instance; - // TODO 需要重构整个 recipe manager - - private static final Object MINECRAFT_RECIPE_MANAGER; - private static final Object MINECRAFT_RECIPE_MAP; - - static { - try { - MINECRAFT_RECIPE_MANAGER = CoreReflections.method$MinecraftServer$getRecipeManager.invoke(CoreReflections.method$MinecraftServer$getServer.invoke(null)); - MINECRAFT_RECIPE_MAP = VersionHelper.isOrAbove1_21_2() ? CoreReflections.field$RecipeManager$recipes.get(MINECRAFT_RECIPE_MANAGER) : null; - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to initialize recipe manager", e); - } - } - private static final Consumer MINECRAFT_RECIPE_REMOVER = VersionHelper.isOrAbove1_21_2() ? (id -> { Object resourceKey = toRecipeResourceKey(id); - FastNMS.INSTANCE.method$RecipeMap$removeRecipe(MINECRAFT_RECIPE_MAP, resourceKey); + FastNMS.INSTANCE.method$RecipeMap$removeRecipe(FastNMS.INSTANCE.field$RecipeManager$recipes(minecraftRecipeManager()), resourceKey); }) : (id -> { Object resourceLocation = KeyUtils.toResourceLocation(id); - FastNMS.INSTANCE.method$RecipeManager$removeRecipe(MINECRAFT_RECIPE_MANAGER, resourceLocation); + FastNMS.INSTANCE.method$RecipeManager$removeRecipe(minecraftRecipeManager(), resourceLocation); }); - private static final BiConsumer MINECRAFT_RECIPE_ADDER = + private static final BiFunction MINECRAFT_RECIPE_ADDER = VersionHelper.isOrAbove1_21_2() ? (id, recipe) -> { Object resourceKey = toRecipeResourceKey(id); Object recipeHolder = FastNMS.INSTANCE.constructor$RecipeHolder(resourceKey, recipe); - FastNMS.INSTANCE.method$RecipeManager$addRecipe(MINECRAFT_RECIPE_MANAGER, recipeHolder); + FastNMS.INSTANCE.method$RecipeManager$addRecipe(minecraftRecipeManager(), recipeHolder); + return recipeHolder; } : VersionHelper.isOrAbove1_20_2() ? (id, recipe) -> { Object resourceLocation = KeyUtils.toResourceLocation(id); Object recipeHolder = FastNMS.INSTANCE.constructor$RecipeHolder(resourceLocation, recipe); - FastNMS.INSTANCE.method$RecipeManager$addRecipe(MINECRAFT_RECIPE_MANAGER, recipeHolder); + FastNMS.INSTANCE.method$RecipeManager$addRecipe(minecraftRecipeManager(), recipeHolder); + return recipeHolder; } : (id, recipe) -> { - FastNMS.INSTANCE.method$RecipeManager$addRecipe(MINECRAFT_RECIPE_MANAGER, recipe); + FastNMS.INSTANCE.method$RecipeManager$addRecipe(minecraftRecipeManager(), recipe); + return recipe; }; static { try { Key dyeRecipeId = Key.from("armor_dye"); MINECRAFT_RECIPE_REMOVER.accept(dyeRecipeId); - MINECRAFT_RECIPE_ADDER.accept(dyeRecipeId, RecipeInjector.createCustomDyeRecipe(dyeRecipeId)); + MINECRAFT_RECIPE_ADDER.apply(dyeRecipeId, RecipeInjector.createCustomDyeRecipe(dyeRecipeId)); Key repairRecipeId = Key.from("repair_item"); MINECRAFT_RECIPE_REMOVER.accept(repairRecipeId); - MINECRAFT_RECIPE_ADDER.accept(repairRecipeId, RecipeInjector.createRepairItemRecipe(repairRecipeId)); + MINECRAFT_RECIPE_ADDER.apply(repairRecipeId, RecipeInjector.createRepairItemRecipe(repairRecipeId)); Key fireworkStarFadeRecipeId = Key.from("firework_star_fade"); MINECRAFT_RECIPE_REMOVER.accept(fireworkStarFadeRecipeId); - MINECRAFT_RECIPE_ADDER.accept(fireworkStarFadeRecipeId, RecipeInjector.createFireworkStarFadeRecipe(fireworkStarFadeRecipeId)); + MINECRAFT_RECIPE_ADDER.apply(fireworkStarFadeRecipeId, RecipeInjector.createFireworkStarFadeRecipe(fireworkStarFadeRecipeId)); } catch (ReflectiveOperationException e) { throw new ReflectionInitException("Failed to inject special recipes", e); } } - private static final List injectedIngredients = new ArrayList<>(); - // 将自定义配方转为“广义”配方,接受更加宽容的输入 - // 部分过程借助bukkit完成,部分直接通过nms方法注册 - private static final Map>> MIXED_RECIPE_CONVERTORS = new HashMap<>(); - private static final IdentityHashMap, Object> MINECRAFT_RECIPE_HOLDER_BY_RECIPE = new IdentityHashMap<>(); + private static final List MODIFIED_INGREDIENTS = new ArrayList<>(); + private static final Map, Object>> ADD_RECIPE_FOR_MINECRAFT_RECIPE_HOLDER = Map.of( + RecipeSerializers.SHAPED, recipe -> { + CustomShapedRecipe shapedRecipe = (CustomShapedRecipe) recipe; + Object mcRecipe = FastNMS.INSTANCE.createShapedRecipe(shapedRecipe); + modifyShapedRecipeIngredients(shapedRecipe, mcRecipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.SHAPELESS, recipe -> { + CustomShapelessRecipe shapelessRecipe = (CustomShapelessRecipe) recipe; + Object mcRecipe = FastNMS.INSTANCE.createShapelessRecipe(shapelessRecipe); + modifyShapelessRecipeIngredients(shapelessRecipe, mcRecipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.SMELTING, recipe -> { + CustomSmeltingRecipe smeltingRecipe = (CustomSmeltingRecipe) recipe; + Object mcRecipe = FastNMS.INSTANCE.createSmeltingRecipe(smeltingRecipe); + modifyCookingRecipeIngredient(smeltingRecipe, mcRecipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.BLASTING, recipe -> { + CustomBlastingRecipe blastingRecipe = (CustomBlastingRecipe) recipe; + Object mcRecipe = FastNMS.INSTANCE.createBlastingRecipe(blastingRecipe); + modifyCookingRecipeIngredient(blastingRecipe, mcRecipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.SMOKING, recipe -> { + CustomSmokingRecipe smokingRecipe = (CustomSmokingRecipe) recipe; + Object mcRecipe = FastNMS.INSTANCE.createSmokingRecipe(smokingRecipe); + modifyCookingRecipeIngredient(smokingRecipe, mcRecipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.CAMPFIRE_COOKING, recipe -> { + CustomCampfireRecipe campfireRecipe = (CustomCampfireRecipe) recipe; + Object mcRecipe = FastNMS.INSTANCE.createCampfireRecipe(campfireRecipe); + modifyCookingRecipeIngredient(campfireRecipe, mcRecipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.STONECUTTING, recipe -> { + Object mcRecipe = FastNMS.INSTANCE.createStonecuttingRecipe((CustomStoneCuttingRecipe) recipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.SMITHING_TRIM, recipe -> { + Object mcRecipe = FastNMS.INSTANCE.createSmithingTrimRecipe((CustomSmithingTrimRecipe) recipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + }, + RecipeSerializers.SMITHING_TRANSFORM, recipe -> { + Object mcRecipe = FastNMS.INSTANCE.createSmithingTransformRecipe((CustomSmithingTransformRecipe) recipe); + return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe); + } + ); - public static Object toRecipeResourceKey(Key id) { - return FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(id)); - } - - private static void registerBukkitShapedRecipe(Object recipe) { + private static void modifyShapedRecipeIngredients(CustomShapedRecipe recipe, Object shapedRecipe) { try { - Object craftRecipe = CraftBukkitReflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, recipe); - CraftBukkitReflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register shaped recipe", e); - } - } - - private static void registerBukkitShapelessRecipe(Object recipe) { - try { - Object craftRecipe = CraftBukkitReflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, recipe); - CraftBukkitReflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register shapeless recipe", e); - } - } - - private static void registerBukkitSmeltingRecipe(Object recipe) { - try { - Object craftRecipe = CraftBukkitReflections.method$CraftFurnaceRecipe$fromBukkitRecipe.invoke(null, recipe); - CraftBukkitReflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register smelting recipe", e); - } - } - - private static void registerBukkitSmokingRecipe(Object recipe) { - try { - Object craftRecipe = CraftBukkitReflections.method$CraftSmokingRecipe$fromBukkitRecipe.invoke(null, recipe); - CraftBukkitReflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register smoking recipe", e); - } - } - - private static void registerBukkitBlastingRecipe(Object recipe) { - try { - Object craftRecipe = CraftBukkitReflections.method$CraftBlastingRecipe$fromBukkitRecipe.invoke(null, recipe); - CraftBukkitReflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register blasting recipe", e); - } - } - - private static void registerBukkitCampfireRecipe(Object recipe) { - try { - Object craftRecipe = CraftBukkitReflections.method$CraftCampfireRecipe$fromBukkitRecipe.invoke(null, recipe); - CraftBukkitReflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register campfire recipe", e); - } - } - - private static void registerBukkitStoneCuttingRecipe(Object recipe) { - try { - Object craftRecipe = CraftBukkitReflections.method$CraftStonecuttingRecipe$fromBukkitRecipe.invoke(null, recipe); - CraftBukkitReflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to register stonecutting recipe", e); - } - } - - static { - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMITHING_TRANSFORM, (BukkitRecipeConvertor>) (id, recipe) -> { - try { - Object nmsRecipe = createMinecraftSmithingTransformRecipe(recipe); - return () -> MINECRAFT_RECIPE_ADDER.accept(id, nmsRecipe); - } catch (InvalidRecipeIngredientException e) { - throw e; - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smithing transform recipe", e); - return null; - } - }); - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMITHING_TRIM, (BukkitRecipeConvertor>) (id, recipe) -> { - try { - Object nmsRecipe = createMinecraftSmithingTrimRecipe(recipe); - return () -> MINECRAFT_RECIPE_ADDER.accept(id, nmsRecipe); - } catch (InvalidRecipeIngredientException e) { - throw e; - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smithing trim recipe", e); - return null; - } - }); - // TODO DO NOT USE BUKKIT RECIPE AS BRIDGE IN FUTURE VERSIONS, WE SHOULD DIRECTLY CONSTRUCT THOSE NMS RECIPES - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SHAPED, (BukkitRecipeConvertor>) (id, recipe) -> { - ShapedRecipe shapedRecipe = new ShapedRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); - if (recipe.group() != null) shapedRecipe.setGroup(Objects.requireNonNull(recipe.group())); - if (recipe.category() != null) shapedRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); - shapedRecipe.shape(recipe.pattern().pattern()); - for (Map.Entry> entry : recipe.pattern().ingredients().entrySet()) { - shapedRecipe.setIngredient(entry.getKey(), ingredientToBukkitRecipeChoice(entry.getValue())); - } - return () -> { - registerBukkitShapedRecipe(shapedRecipe); - injectShapedRecipe(id, recipe); - }; - }); - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SHAPELESS, (BukkitRecipeConvertor>) (id, recipe) -> { - ShapelessRecipe shapelessRecipe = new ShapelessRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); - if (recipe.group() != null) shapelessRecipe.setGroup(Objects.requireNonNull(recipe.group())); - if (recipe.category() != null) shapelessRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); - for (Ingredient ingredient : recipe.ingredientsInUse()) { - shapelessRecipe.addIngredient(ingredientToBukkitRecipeChoice(ingredient)); - } - return () -> { - registerBukkitShapelessRecipe(shapelessRecipe); - injectShapelessRecipe(id, recipe); - }; - }); - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMELTING, (BukkitRecipeConvertor>) (id, recipe) -> { - FurnaceRecipe furnaceRecipe = new FurnaceRecipe( - new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(recipe.ingredient()), - recipe.experience(), recipe.cookingTime() - ); - if (recipe.group() != null) furnaceRecipe.setGroup(Objects.requireNonNull(recipe.group())); - if (recipe.category() != null) furnaceRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); - return () -> { - registerBukkitSmeltingRecipe(furnaceRecipe); - injectCookingRecipe(id, recipe); - }; - }); - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.SMOKING, (BukkitRecipeConvertor>) (id, recipe) -> { - SmokingRecipe smokingRecipe = new SmokingRecipe( - new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(recipe.ingredient()), - recipe.experience(), recipe.cookingTime() - ); - if (recipe.group() != null) smokingRecipe.setGroup(Objects.requireNonNull(recipe.group())); - if (recipe.category() != null) smokingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); - return () -> { - registerBukkitSmokingRecipe(smokingRecipe); - injectCookingRecipe(id, recipe); - }; - }); - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.BLASTING, (BukkitRecipeConvertor>) (id, recipe) -> { - BlastingRecipe blastingRecipe = new BlastingRecipe( - new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(recipe.ingredient()), - recipe.experience(), recipe.cookingTime() - ); - if (recipe.group() != null) blastingRecipe.setGroup(Objects.requireNonNull(recipe.group())); - if (recipe.category() != null) blastingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); - return () -> { - registerBukkitBlastingRecipe(blastingRecipe); - injectCookingRecipe(id, recipe); - }; - }); - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.CAMPFIRE_COOKING, (BukkitRecipeConvertor>) (id, recipe) -> { - CampfireRecipe campfireRecipe = new CampfireRecipe( - new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(recipe.ingredient()), - recipe.experience(), recipe.cookingTime() - ); - if (recipe.group() != null) campfireRecipe.setGroup(Objects.requireNonNull(recipe.group())); - if (recipe.category() != null) campfireRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); - return () -> { - registerBukkitCampfireRecipe(campfireRecipe); - injectCookingRecipe(id, recipe); - }; - }); - MIXED_RECIPE_CONVERTORS.put(RecipeSerializers.STONECUTTING, (BukkitRecipeConvertor>) (id, recipe) -> { - List itemStacks = new ArrayList<>(); - for (UniqueKey item : recipe.ingredient().items()) { - itemStacks.add(BukkitItemManager.instance().buildItemStack(item.key(), null)); - } - StonecuttingRecipe stonecuttingRecipe = new StonecuttingRecipe( - new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), - new RecipeChoice.ExactChoice(itemStacks) - ); - if (recipe.group() != null) stonecuttingRecipe.setGroup(Objects.requireNonNull(recipe.group())); - return () -> { - registerBukkitStoneCuttingRecipe(stonecuttingRecipe); - }; - }); - } - - /* - * 注册全过程: - * - * 0.准备阶段偷取flag以减少注册的性能开销 - * 1.先读取用户配置自定义配方 - * 2.延迟加载中为自定义配方生成转换为nms配方的任务 - * 3.读取全部的数据包配方并转换为自定义配方,对必要的含有tag配方添加先移除后注册nms配方的任务 - * 4.主线程完成剩余任务 - * 5.归还flag - */ - - private final BukkitCraftEngine plugin; - private final RecipeEventListener recipeEventListener; - private final CrafterEventListener crafterEventListener; - // Some delayed tasks on main thread - private final List delayedTasksOnMainThread = new ArrayList<>(); - // To optimize recipes loading, will return the flag later - private Object stolenFeatureFlagSet; - - public BukkitRecipeManager(BukkitCraftEngine plugin) { - instance = this; - this.plugin = plugin; - this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager()); - this.crafterEventListener = VersionHelper.isOrAbove1_21() ? new CrafterEventListener(plugin, this, plugin.itemManager()) : null; - } - - public Object nmsRecipeHolderByRecipe(Recipe recipe) { - if (super.isReloading) return null; - return MINECRAFT_RECIPE_HOLDER_BY_RECIPE.get(recipe); - } - - public static Object minecraftRecipeManager() { - return MINECRAFT_RECIPE_MANAGER; - } - - public static BukkitRecipeManager instance() { - return instance; - } - - @Override - public void delayedInit() { - Bukkit.getPluginManager().registerEvents(this.recipeEventListener, this.plugin.javaPlugin()); - if (this.crafterEventListener != null) { - Bukkit.getPluginManager().registerEvents(this.crafterEventListener, this.plugin.javaPlugin()); - } - } - - @Override - public void load() { - if (!Config.enableRecipeSystem()) return; - super.isReloading = true; - if (VersionHelper.isOrAbove1_21_2()) { - try { - this.stolenFeatureFlagSet = CoreReflections.field$RecipeManager$featureflagset.get(MINECRAFT_RECIPE_MANAGER); - CoreReflections.field$RecipeManager$featureflagset.set(MINECRAFT_RECIPE_MANAGER, null); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to steal featureflagset", e); - } - } - } - - @Override - public void unload() { - if (!Config.enableRecipeSystem()) return; - // 安排卸载任务,这些任务会在load后执行。如果没有load说明服务器已经关闭了,那就不需要管卸载了。 - if (!Bukkit.isStopping()) { - for (Map.Entry> entry : this.byId.entrySet()) { - Key id = entry.getKey(); - if (isDataPackRecipe(id)) continue; - boolean isBrewingRecipe = entry.getValue() instanceof CustomBrewingRecipe; - this.delayedTasksOnMainThread.add(() -> this.unregisterPlatformRecipe(id, isBrewingRecipe)); - } - } - super.unload(); - } - - @Override - public void delayedLoad() { - if (!Config.enableRecipeSystem()) return; - this.injectDataPackRecipes(); - } - - @Override - public void disable() { - unload(); - MINECRAFT_RECIPE_HOLDER_BY_RECIPE.clear(); - // 不是服务器关闭造成disable,那么需要把配方卸载干净 - if (!Bukkit.isStopping()) { - for (Runnable task : this.delayedTasksOnMainThread) { - task.run(); - } - } - HandlerList.unregisterAll(this.recipeEventListener); - if (this.crafterEventListener != null) { - HandlerList.unregisterAll(this.crafterEventListener); - } - } - - @Override - protected void unregisterPlatformRecipe(Key key, boolean isBrewingRecipe) { - if (isBrewingRecipe) { - Bukkit.getPotionBrewer().removePotionMix(new NamespacedKey(key.namespace(), key.value())); - } else { - MINECRAFT_RECIPE_REMOVER.accept(key); - } - } - - @Override - protected void registerPlatformRecipe(Key id, Recipe recipe) { - if (recipe instanceof CustomBrewingRecipe brewingRecipe) { - if (!VersionHelper.isOrAbove1_20_2()) return; - PotionMix potionMix = new PotionMix(new NamespacedKey(id.namespace(), id.value()), - brewingRecipe.result(ItemBuildContext.EMPTY), - PotionMix.createPredicateChoice(container -> { - Item wrapped = this.plugin.itemManager().wrap(container); - return brewingRecipe.container().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped)); - }), - PotionMix.createPredicateChoice(ingredient -> { - Item wrapped = this.plugin.itemManager().wrap(ingredient); - return brewingRecipe.ingredient().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped)); - }) - ); - this.delayedTasksOnMainThread.add(() -> { - Bukkit.getPotionBrewer().addPotionMix(potionMix); - }); - } else { - try { - Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe); - if (converted != null) { - this.delayedTasksOnMainThread.add(converted); - } - } catch (InvalidRecipeIngredientException e) { - throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", e.ingredient()); - } catch (Exception e) { - this.plugin.logger().warn("Failed to convert recipe " + id, e); - } - } - } - - @SuppressWarnings("unchecked") - private > BukkitRecipeConvertor findNMSRecipeConvertor(T recipe) { - return (BukkitRecipeConvertor) MIXED_RECIPE_CONVERTORS.get(recipe.serializerType()); - } - - @SuppressWarnings("unchecked") - private void injectDataPackRecipes() { - try { - Object fileToIdConverter = CoreReflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isOrAbove1_21() ? "recipe" : "recipes"); - Object minecraftServer = CoreReflections.method$MinecraftServer$getServer.invoke(null); - Object packRepository = CoreReflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer); - List selected = (List) CoreReflections.field$PackRepository$selected.get(packRepository); - List packResources = new ArrayList<>(); - for (Object pack : selected) { - packResources.add(CoreReflections.method$Pack$open.invoke(pack)); - } - - boolean hasDisabledAny = !Config.disabledVanillaRecipes().isEmpty(); - try (AutoCloseable resourceManager = (AutoCloseable) CoreReflections.constructor$MultiPackResourceManager.newInstance(CoreReflections.instance$PackType$SERVER_DATA, packResources)) { - Map scannedResources = (Map) CoreReflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); - for (Map.Entry entry : scannedResources.entrySet()) { - Key id = extractKeyFromResourceLocation(entry.getKey().toString()); - // now CraftEngine takes over everything -// // Maybe it's unregistered by other plugins -// if (Bukkit.getRecipe(new NamespacedKey(id.namespace(), id.value())) == null) { -// continue; -// } - if (Config.disableAllVanillaRecipes()) { - this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false)); - continue; - } - if (hasDisabledAny && Config.disabledVanillaRecipes().contains(id)) { - this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false)); - continue; - } - markAsDataPackRecipe(id); - Reader reader = (Reader) CoreReflections.method$Resource$openAsReader.invoke(entry.getValue()); - JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); - String type = jsonObject.get("type").getAsString(); - switch (type) { - case "minecraft:crafting_shaped" -> { - VanillaShapedRecipe recipe = this.recipeReader.readShaped(jsonObject); - handleDataPackShapedRecipe(id, recipe, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:crafting_shapeless" -> { - VanillaShapelessRecipe recipe = this.recipeReader.readShapeless(jsonObject); - handleDataPackShapelessRecipe(id, recipe, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:smelting" -> { - VanillaSmeltingRecipe recipe = this.recipeReader.readSmelting(jsonObject); - handleDataPackCookingRecipe(id, recipe, CustomSmeltingRecipe::new, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:blasting" -> { - VanillaBlastingRecipe recipe = this.recipeReader.readBlasting(jsonObject); - handleDataPackCookingRecipe(id, recipe, CustomBlastingRecipe::new, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:smoking" -> { - VanillaSmokingRecipe recipe = this.recipeReader.readSmoking(jsonObject); - handleDataPackCookingRecipe(id, recipe, CustomSmokingRecipe::new, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:campfire_cooking" -> { - VanillaCampfireRecipe recipe = this.recipeReader.readCampfire(jsonObject); - handleDataPackCookingRecipe(id, recipe, CustomCampfireRecipe::new, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:smithing_transform" -> { - VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject); - handleDataPackSmithingTransform(id, recipe, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:smithing_trim" -> { - VanillaSmithingTrimRecipe recipe = this.recipeReader.readSmithingTrim(jsonObject); - handleDataPackSmithingTrim(id, recipe, (this.delayedTasksOnMainThread::add)); - } - case "minecraft:stonecutting" -> { - VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject); - handleDataPackStoneCuttingRecipe(id, recipe); - } - } - } - } - } catch (Exception e) { - this.plugin.logger().warn("Failed to read data pack recipes", e); - } - } - - @Override - public void runDelayedSyncTasks() { - if (!Config.enableRecipeSystem()) return; - - try { - // run delayed tasks - for (Runnable r : this.delayedTasksOnMainThread) { - r.run(); - } - this.delayedTasksOnMainThread.clear(); - - // give flags back on 1.21.2+ - if (VersionHelper.isOrAbove1_21_2() && this.stolenFeatureFlagSet != null) { - CoreReflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager(), this.stolenFeatureFlagSet); - this.stolenFeatureFlagSet = null; - } - - // refresh recipes + List> actualIngredients = recipe.parsedPattern().ingredients() + .stream() + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager()); + CoreReflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null); } - - // send to players - CoreReflections.method$DedicatedPlayerList$reloadRecipes.invoke(CraftBukkitReflections.field$CraftServer$playerList.get(Bukkit.getServer())); - - // now we need to remove the fake `exact` - if (VersionHelper.isOrAbove1_21_4()) { - for (Object ingredient : injectedIngredients) { - CoreReflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null); - } - } else if (VersionHelper.isOrAbove1_21_2()) { - for (Object ingredient : injectedIngredients) { - CoreReflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null); - } - } - - // clear cache - injectedIngredients.clear(); - - MINECRAFT_RECIPE_HOLDER_BY_RECIPE.clear(); - // create mappings - for (Map.Entry> entry : this.byId.entrySet()) { - Optional nmsRecipe = getOptionalNMSRecipe(entry.getKey()); - nmsRecipe.ifPresent(o -> MINECRAFT_RECIPE_HOLDER_BY_RECIPE.put(entry.getValue(), o)); - } - super.isReloading = false; - } catch (Exception e) { - this.plugin.logger().warn("Failed to run delayed recipe tasks", e); + List ingredients = getIngredientsFromShapedRecipe(shapedRecipe); + modifyIngredients(ingredients, actualIngredients); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject shaped recipe", e); } } - private void handleDataPackStoneCuttingRecipe(Key id, VanillaStoneCuttingRecipe recipe) { - ItemStack result = createDataPackResultStack(recipe.result()); - Set holders = new HashSet<>(); - for (String item : recipe.ingredient()) { - if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - holders.addAll(this.plugin.itemManager().tagToItems(tag)); - } else { - holders.add(UniqueKey.create(Key.from(item))); - } - } - CustomStoneCuttingRecipe ceRecipe = new CustomStoneCuttingRecipe<>( - id, recipe.group(), Ingredient.of(holders), - new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), BukkitItemManager.instance().wrap(result)), recipe.result().count(), null) - ); - this.registerInternalRecipe(id, ceRecipe); - } - - private void handleDataPackShapelessRecipe(Key id, VanillaShapelessRecipe recipe, Consumer callback) { - ItemStack result = createDataPackResultStack(recipe.result()); - boolean hasCustomItemInTag = false; - List> ingredientList = new ArrayList<>(); - for (List list : recipe.ingredients()) { - Set holders = new HashSet<>(); - for (String item : list) { - if (item.charAt(0) == '#') { - Key tag = Key.of(item.substring(1)); - if (!hasCustomItemInTag) { - if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; + @SuppressWarnings("unchecked") + public static List getIngredientsFromShapedRecipe(Object recipe) { + List ingredients = new ArrayList<>(); + try { + if (VersionHelper.isOrAbove1_20_3()) { + Object pattern = CoreReflections.field$1_20_3$ShapedRecipe$pattern.get(recipe); + if (VersionHelper.isOrAbove1_21_2()) { + List> optionals = (List>) CoreReflections.field$ShapedRecipePattern$ingredients1_21_2.get(pattern); + for (Optional optional : optionals) { + optional.ifPresent(ingredients::add); + } + } else { + List objectList = (List) CoreReflections.field$ShapedRecipePattern$ingredients1_20_3.get(pattern); + for (Object object : objectList) { + Object[] values = (Object[]) CoreReflections.field$Ingredient$values.get(object); + // is empty or not + if (values.length != 0) { + ingredients.add(object); } } - holders.addAll(plugin.itemManager().tagToItems(tag)); - } else { - holders.add(UniqueKey.create(Key.from(item))); - } - } - ingredientList.add(Ingredient.of(holders)); - } - CustomShapelessRecipe ceRecipe = new CustomShapelessRecipe<>( - id, recipe.category(), recipe.group(), ingredientList, - new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), BukkitItemManager.instance().wrap(result)), recipe.result().count(), null) - ); - if (hasCustomItemInTag) { - Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); - callback.accept(() -> { - MINECRAFT_RECIPE_REMOVER.accept(id); - converted.run(); - }); - } - this.registerInternalRecipe(id, ceRecipe); - } - - private void handleDataPackShapedRecipe(Key id, VanillaShapedRecipe recipe, Consumer callback) { - ItemStack result = createDataPackResultStack(recipe.result()); - boolean hasCustomItemInTag = false; - Map> ingredients = new HashMap<>(); - for (Map.Entry> entry : recipe.ingredients().entrySet()) { - Set holders = new HashSet<>(); - for (String item : entry.getValue()) { - if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - if (!hasCustomItemInTag) { - if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; - } - } - holders.addAll(plugin.itemManager().tagToItems(tag)); - } else { - holders.add(UniqueKey.create(Key.from(item))); - } - } - ingredients.put(entry.getKey(), Ingredient.of(holders)); - } - CustomShapedRecipe ceRecipe = new CustomShapedRecipe<>( - id, recipe.category(), recipe.group(), - new CustomShapedRecipe.Pattern<>(recipe.pattern(), ingredients), - new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), BukkitItemManager.instance().wrap(result)), recipe.result().count(), null) - ); - if (hasCustomItemInTag) { - Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); - callback.accept(() -> { - MINECRAFT_RECIPE_REMOVER.accept(id); - converted.run(); - }); - } - this.registerInternalRecipe(id, ceRecipe); - } - - private void handleDataPackCookingRecipe(Key id, - VanillaCookingRecipe recipe, - HeptaFunction, Integer, Float, CustomRecipeResult, CustomCookingRecipe> constructor2, - Consumer callback) { - ItemStack result = createDataPackResultStack(recipe.result()); - Set holders = new HashSet<>(); - boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), holders::add); - CustomCookingRecipe ceRecipe = constructor2.apply( - id, recipe.category(), recipe.group(), - Ingredient.of(holders), - recipe.cookingTime(), recipe.experience(), - new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), BukkitItemManager.instance().wrap(result)), recipe.result().count(), null) - ); - if (hasCustomItemInTag) { - Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); - callback.accept(() -> { - MINECRAFT_RECIPE_REMOVER.accept(id); - converted.run(); - }); - } - this.registerInternalRecipe(id, ceRecipe); - } - - private void handleDataPackSmithingTransform(Key id, VanillaSmithingTransformRecipe recipe, Consumer callback) { - ItemStack result = createDataPackResultStack(recipe.result()); - boolean hasCustomItemInTag; - - Set additionHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add); - Set templateHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add); - Set baseHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add); - - CustomSmithingTransformRecipe ceRecipe = new CustomSmithingTransformRecipe<>( - id, - baseHolders.isEmpty() ? null : Ingredient.of(baseHolders), - templateHolders.isEmpty() ? null : Ingredient.of(templateHolders), - additionHolders.isEmpty() ? null : Ingredient.of(additionHolders), - new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), BukkitItemManager.instance().wrap(result)), recipe.result().count(), null), - true, - List.of() - ); - - if (hasCustomItemInTag) { - Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); - callback.accept(() -> { - MINECRAFT_RECIPE_REMOVER.accept(id); - converted.run(); - }); - } - this.registerInternalRecipe(id, ceRecipe); - } - - private void handleDataPackSmithingTrim(Key id, VanillaSmithingTrimRecipe recipe, Consumer callback) { - boolean hasCustomItemInTag; - Set additionHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add); - Set templateHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add); - Set baseHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add); - - CustomSmithingTrimRecipe ceRecipe = new CustomSmithingTrimRecipe<>( - id, - Ingredient.of(baseHolders), - Ingredient.of(templateHolders), - Ingredient.of(additionHolders), - Optional.ofNullable(recipe.pattern()).map(Key::of).orElse(null) - ); - - if (hasCustomItemInTag) { - Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); - callback.accept(() -> { - MINECRAFT_RECIPE_REMOVER.accept(id); - converted.run(); - }); - } - this.registerInternalRecipe(id, ceRecipe); - } - - private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer holderConsumer) { - for (String item : ingredients) { - if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - if (!hasCustomItemInTag) { - if (!this.plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; - } - } - for (UniqueKey holder : this.plugin.itemManager().tagToItems(tag)) { - holderConsumer.accept(holder); } } else { - holderConsumer.accept(UniqueKey.create(Key.from(item))); + List objectList = (List) CoreReflections.field$1_20_1$ShapedRecipe$recipeItems.get(recipe); + for (Object object : objectList) { + Object[] values = (Object[]) CoreReflections.field$Ingredient$values.get(object); + if (values.length != 0) { + ingredients.add(object); + } + } } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to get ingredients from shaped recipe", e); } - return hasCustomItemInTag; + return ingredients; } - private ItemStack createDataPackResultStack(RecipeResult result) { - ItemStack itemStack; - if (result.components() == null) { - itemStack = new ItemStack(Objects.requireNonNull(MaterialUtils.getMaterial(result.id()))); - itemStack.setAmount(result.count()); - } else { - // 低版本无法应用nbt或组件,所以这里是1.20.5+ - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("id", result.id()); - jsonObject.addProperty("count", result.count()); - jsonObject.add("components", result.components()); - Object nmsStack = CoreReflections.instance$ItemStack$CODEC.parse(MRegistryOps.JSON, jsonObject) - .resultOrPartial((itemId) -> plugin.logger().severe("Tried to load invalid item: '" + itemId + "'")).orElse(null); - if (nmsStack == null) { - return new ItemStack(Material.STONE); + private static void modifyShapelessRecipeIngredients(CustomShapelessRecipe recipe, Object shapelessRecipe) { + try { + List> actualIngredients = recipe.ingredientsInUse(); + if (VersionHelper.isOrAbove1_21_2()) { + CoreReflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null); } - try { - itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsStack); - } catch (Exception e) { - this.plugin.logger().warn("Failed to create ItemStack mirror", e); - return new ItemStack(Material.STICK); + @SuppressWarnings("unchecked") + List ingredients = (List) CoreReflections.field$ShapelessRecipe$ingredients.get(shapelessRecipe); + modifyIngredients(ingredients, actualIngredients); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject shapeless recipe", e); + } + } + + private static void modifyCookingRecipeIngredient(CustomCookingRecipe recipe, Object cookingRecipe) { + try { + Ingredient actualIngredient = recipe.ingredient(); + Object ingredient; + if (VersionHelper.isOrAbove1_21_2()) { + ingredient = CoreReflections.field$SingleItemRecipe$input.get(cookingRecipe); + } else { + ingredient = CoreReflections.field$AbstractCookingRecipe$input.get(cookingRecipe); } + modifyIngredients(List.of(ingredient), List.of(actualIngredient)); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject cooking recipe", e); } - return itemStack; - } - - private Key extractKeyFromResourceLocation(String input) { - int prefixEndIndex = input.indexOf(':'); - String prefix = input.substring(0, prefixEndIndex); - int lastSlashIndex = input.lastIndexOf('/'); - int lastDotIndex = input.lastIndexOf('.'); - String fileName = input.substring(lastSlashIndex + 1, lastDotIndex); - return Key.of(prefix, fileName); - } - - private static RecipeChoice ingredientToBukkitRecipeChoice(Ingredient ingredient) { - Set materials = new HashSet<>(); - for (UniqueKey holder : ingredient.items()) { - materials.add(getMaterialById(holder.key())); - } - return new RecipeChoice.MaterialChoice(new ArrayList<>(materials)); - } - - private static Material getMaterialById(Key key) { - Material material = MaterialUtils.getMaterial(key); - if (material != null) { - return material; - } - Optional> optionalItem = BukkitItemManager.instance().getCustomItem(key); - return optionalItem.map(itemStackCustomItem -> MaterialUtils.getMaterial(itemStackCustomItem.material())).orElseThrow(() -> new InvalidRecipeIngredientException(key.asString())); } private static List getIngredientLooks(List holders) { @@ -815,96 +230,14 @@ public class BukkitRecipeManager extends AbstractRecipeManager { itemStacks.add(nmsStack); } else { Item barrier = BukkitItemManager.instance().createWrappedItem(ItemKeys.BARRIER, null); + assert barrier != null; barrier.customNameJson(AdventureHelper.componentToJson(Component.text(holder.key().asString()).color(NamedTextColor.RED))); } } return itemStacks; } - // 无论是什么注入什么配方类型的方法,其本质都是注入ingredient - private static void injectShapedRecipe(Key id, CustomShapedRecipe recipe) { - try { - List> actualIngredients = recipe.parsedPattern().ingredients() - .stream() - .filter(Optional::isPresent) - .map(Optional::get) - .toList(); - - Object shapedRecipe = getOptionalNMSRecipe(id).get(); - if (VersionHelper.isOrAbove1_20_2()) { - shapedRecipe = CoreReflections.field$RecipeHolder$recipe.get(shapedRecipe); - } - - if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null); - } - - List ingredients = RecipeUtils.getIngredientsFromShapedRecipe(shapedRecipe); - injectIngredients(ingredients, actualIngredients); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to inject shaped recipe", e); - } - } - - private static void injectShapelessRecipe(Key id, CustomShapelessRecipe recipe) { - try { - List> actualIngredients = recipe.ingredientsInUse(); - - Object shapelessRecipe = getOptionalNMSRecipe(id).get(); - if (VersionHelper.isOrAbove1_20_2()) { - shapelessRecipe = CoreReflections.field$RecipeHolder$recipe.get(shapelessRecipe); - } - - if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null); - } - @SuppressWarnings("unchecked") - List ingredients = (List) CoreReflections.field$ShapelessRecipe$ingredients.get(shapelessRecipe); - injectIngredients(ingredients, actualIngredients); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to inject shapeless recipe", e); - } - } - - private static void injectCookingRecipe(Key id, CustomCookingRecipe recipe) { - try { - Ingredient actualIngredient = recipe.ingredient(); - Object smeltingRecipe = getOptionalNMSRecipe(id).get(); - if (VersionHelper.isOrAbove1_20_2()) { - smeltingRecipe = CoreReflections.field$RecipeHolder$recipe.get(smeltingRecipe); - } - - Object ingredient; - if (VersionHelper.isOrAbove1_21_2()) { - ingredient = CoreReflections.field$SingleItemRecipe$input.get(smeltingRecipe); - } else { - ingredient = CoreReflections.field$AbstractCookingRecipe$input.get(smeltingRecipe); - } - injectIngredients(List.of(ingredient), List.of(actualIngredient)); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to inject cooking recipe", e); - } - } - - // 获取nms配方,请注意1.20.1获取配方本身,而1.20.2+获取的是配方的holder - // recipe on 1.20.1 and holder on 1.20.2+ - private static Optional getOptionalNMSRecipe(Key id) throws ReflectiveOperationException { - if (VersionHelper.isOrAbove1_21_2()) { - Object resourceKey = FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(id)); - @SuppressWarnings("unchecked") - Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(MINECRAFT_RECIPE_MANAGER, resourceKey); - return optional; - } else { - Object resourceLocation = KeyUtils.toResourceLocation(id); - @SuppressWarnings("unchecked") - Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(MINECRAFT_RECIPE_MANAGER, resourceLocation); - return optional; - } - } - - // 注入原料,这个方法受不同服务端fork和版本影响极大,需要每个版本测试 - // 此过程是为了避免自己处理“广义”配方与客户端的注册通讯 - private static void injectIngredients(List fakeIngredients, List> actualIngredients) throws ReflectiveOperationException { + private static void modifyIngredients(List fakeIngredients, List> actualIngredients) throws ReflectiveOperationException { if (fakeIngredients.size() != actualIngredients.size()) { throw new IllegalArgumentException("Ingredient count mismatch"); } @@ -923,100 +256,256 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } CoreReflections.field$Ingredient$itemStacks1_20_1.set(ingredient, itemStackArray); } - injectedIngredients.add(ingredient); + MODIFIED_INGREDIENTS.add(ingredient); } } - // 1.20-1.21.2 - private static Object toMinecraftIngredient(Ingredient ingredient) throws ReflectiveOperationException { - if (ingredient == null) { - return CraftBukkitReflections.method$CraftRecipe$toIngredient.invoke(null, null, true); - } else { - RecipeChoice choice = ingredientToBukkitRecipeChoice(ingredient); - return CraftBukkitReflections.method$CraftRecipe$toIngredient.invoke(null, choice, true); + public static Object toRecipeResourceKey(Key id) { + return FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(id)); + } + + /* + * 注册全过程: + * + * 0.准备阶段偷取flag以减少注册的性能开销 + * 1.先读取用户配置自定义配方 + * 2.延迟加载中为自定义配方生成转换为nms配方的任务 + * 3.读取全部的数据包配方并转换为自定义配方,对必要的含有tag配方添加先移除后注册nms配方的任务 + * 4.主线程完成剩余任务 + * 5.归还flag + */ + private final BukkitCraftEngine plugin; + private final RecipeEventListener recipeEventListener; + // 欺骗服务端使其以为自己处于启动阶段 + private Object stolenFeatureFlagSet; + // 需要在主线程卸载的配方 + private final List> recipesToUnregister = new ArrayList<>(); + // 已经被替换过的数据包配方 + private final Set replacedDatapackRecipes = new HashSet<>(); + // 换成的数据包配方 + private Map> lastDatapackRecipes = Map.of(); + private Object lastRecipeManager = null; + + public BukkitRecipeManager(BukkitCraftEngine plugin) { + instance = this; + this.plugin = plugin; + this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager()); + } + + public static Object minecraftRecipeManager() { + return FastNMS.INSTANCE.method$MinecraftServer$getRecipeManager(FastNMS.INSTANCE.method$MinecraftServer$getServer()); + } + + public static BukkitRecipeManager instance() { + return instance; + } + + @Override + public void delayedInit() { + Bukkit.getPluginManager().registerEvents(this.recipeEventListener, this.plugin.javaPlugin()); + } + + @Override + public void load() { + if (!Config.enableRecipeSystem()) return; + if (VersionHelper.isOrAbove1_21_2()) { + try { + this.stolenFeatureFlagSet = CoreReflections.field$RecipeManager$featureflagset.get(minecraftRecipeManager()); + CoreReflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager(), null); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to steal feature flag set", e); + } } } - // 1.21.2+ - private static Optional toOptionalMinecraftIngredient(Ingredient ingredient) throws ReflectiveOperationException { - if (ingredient == null) { - return Optional.empty(); + @Override + public void unload() { + if (!Config.enableRecipeSystem()) return; + // 安排卸载任务,这些任务会在load后执行。如果没有load说明服务器已经关闭了,那就不需要管卸载了。 + if (!Bukkit.isStopping()) { + for (Map.Entry> entry : this.byId.entrySet()) { + Key id = entry.getKey(); + // 不要卸载数据包配方,只记录自定义的配方 + if (isDataPackRecipe(id)) continue; + boolean isBrewingRecipe = entry.getValue() instanceof CustomBrewingRecipe; + this.recipesToUnregister.add(Pair.of(id, isBrewingRecipe)); + } + } + super.unload(); + } + + @Override + public void delayedLoad() { + if (!Config.enableRecipeSystem()) return; + this.loadDataPackRecipes(); + } + + @Override + public void disable() { + unload(); + HandlerList.unregisterAll(this.recipeEventListener); + } + + @Override + protected void unregisterPlatformRecipeMainThread(Key key, boolean isBrewingRecipe) { + if (isBrewingRecipe) { + Bukkit.getPotionBrewer().removePotionMix(new NamespacedKey(key.namespace(), key.value())); } else { - RecipeChoice choice = ingredientToBukkitRecipeChoice(ingredient); - Object mcIngredient = CraftBukkitReflections.method$CraftRecipe$toIngredient.invoke(null, choice, true); - return Optional.of(mcIngredient); + MINECRAFT_RECIPE_REMOVER.accept(key); } } - // 1.21.5+ - private static Object toTransmuteResult(ItemStack item) throws InvocationTargetException, IllegalAccessException, InstantiationException { - Object itemStack = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(item); - Object nmsItem = CoreReflections.method$ItemStack$getItem.invoke(itemStack); - return CoreReflections.constructor$TransmuteResult.newInstance(nmsItem); - } - - // create nms smithing recipe for different versions - private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe recipe) throws ReflectiveOperationException { - if (VersionHelper.isOrAbove1_21_5()) { - return CoreReflections.constructor$SmithingTransformRecipe.newInstance( - toOptionalMinecraftIngredient(recipe.template()), - toMinecraftIngredient(recipe.base()), - toOptionalMinecraftIngredient(recipe.addition()), - toTransmuteResult(recipe.result(ItemBuildContext.EMPTY)) - ); - } else if (VersionHelper.isOrAbove1_21_2()) { - return CoreReflections.constructor$SmithingTransformRecipe.newInstance( - toOptionalMinecraftIngredient(recipe.template()), - toOptionalMinecraftIngredient(recipe.base()), - toOptionalMinecraftIngredient(recipe.addition()), - FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(recipe.result(ItemBuildContext.EMPTY)) - ); - } else if (VersionHelper.isOrAbove1_20_2()) { - return CoreReflections.constructor$SmithingTransformRecipe.newInstance( - toMinecraftIngredient(recipe.template()), - toMinecraftIngredient(recipe.base()), - toMinecraftIngredient(recipe.addition()), - FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(recipe.result(ItemBuildContext.EMPTY)) + @Override + protected void registerPlatformRecipeMainThread(Recipe recipe) { + Key id = recipe.id(); + if (recipe instanceof CustomBrewingRecipe brewingRecipe) { + if (!VersionHelper.isOrAbove1_20_2()) return; + PotionMix potionMix = new PotionMix(new NamespacedKey(id.namespace(), id.value()), + brewingRecipe.result(ItemBuildContext.EMPTY), + PotionMix.createPredicateChoice(container -> { + Item wrapped = this.plugin.itemManager().wrap(container); + return brewingRecipe.container().test(UniqueIdItem.of(wrapped)); + }), + PotionMix.createPredicateChoice(ingredient -> { + Item wrapped = this.plugin.itemManager().wrap(ingredient); + return brewingRecipe.ingredient().test(UniqueIdItem.of(wrapped)); + }) ); + Bukkit.getPotionBrewer().addPotionMix(potionMix); } else { - return CoreReflections.constructor$SmithingTransformRecipe.newInstance( - KeyUtils.toResourceLocation(recipe.id()), - toMinecraftIngredient(recipe.template()), - toMinecraftIngredient(recipe.base()), - toMinecraftIngredient(recipe.addition()), - FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(recipe.result(ItemBuildContext.EMPTY)) - ); + // 如果是数据包配方 + if (isDataPackRecipe(id)) { + // 如果这个数据包配方已经被换成了注入配方,那么是否需要重新注册取决于其是否含有tag,且tag里有自定义物品 + if (!this.replacedDatapackRecipes.add(id)) { + outer: { + for (Ingredient ingredient : recipe.ingredientsInUse()) { + if (ingredient.hasCustomItem()) { + break outer; + } + } + // 没有自定义物品,且被注入过了,那么就不需要移除后重新注册 + return; + } + } + MINECRAFT_RECIPE_REMOVER.accept(id); + } + ADD_RECIPE_FOR_MINECRAFT_RECIPE_HOLDER.get(recipe.serializerType()).apply(recipe); } } - private static Object createMinecraftSmithingTrimRecipe(CustomSmithingTrimRecipe recipe) throws ReflectiveOperationException { - if (VersionHelper.isOrAbove1_21_5()) { - Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN); - return CoreReflections.constructor$SmithingTrimRecipe.newInstance( - toMinecraftIngredient(recipe.template()), - toMinecraftIngredient(recipe.base()), - toMinecraftIngredient(recipe.addition()), - FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(registry, KeyUtils.toResourceLocation(recipe.pattern())).orElseThrow(() -> new RuntimeException("Pattern " + recipe.pattern() + " doesn't exist.")) - ); - } else if (VersionHelper.isOrAbove1_21_2()) { - return CoreReflections.constructor$SmithingTrimRecipe.newInstance( - toOptionalMinecraftIngredient(recipe.template()), - toOptionalMinecraftIngredient(recipe.base()), - toOptionalMinecraftIngredient(recipe.addition()) - ); - } else if (VersionHelper.isOrAbove1_20_2()) { - return CoreReflections.constructor$SmithingTrimRecipe.newInstance( - toMinecraftIngredient(recipe.template()), - toMinecraftIngredient(recipe.base()), - toMinecraftIngredient(recipe.addition()) - ); - } else { - return CoreReflections.constructor$SmithingTrimRecipe.newInstance( - KeyUtils.toResourceLocation(recipe.id()), - toMinecraftIngredient(recipe.template()), - toMinecraftIngredient(recipe.base()), - toMinecraftIngredient(recipe.addition()) - ); + private void loadDataPackRecipes() { + Object currentRecipeManager = minecraftRecipeManager(); + if (currentRecipeManager != this.lastRecipeManager) { + this.lastRecipeManager = currentRecipeManager; + this.replacedDatapackRecipes.clear(); + try { + this.lastDatapackRecipes = scanResources(); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to load datapack recipes", e); + } + } + for (Map.Entry> entry : this.lastDatapackRecipes.entrySet()) { + markAsDataPackRecipe(entry.getKey()); + registerInternalRecipe(entry.getKey(), entry.getValue()); + } + } + + @SuppressWarnings("unchecked") + private Map> scanResources() throws ReflectiveOperationException { + Object fileToIdConverter = CoreReflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isOrAbove1_21() ? "recipe" : "recipes"); + Object minecraftServer = FastNMS.INSTANCE.method$MinecraftServer$getServer(); + Object packRepository = CoreReflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer); + List selected = (List) CoreReflections.field$PackRepository$selected.get(packRepository); + List packResources = new ArrayList<>(); + for (Object pack : selected) { + packResources.add(CoreReflections.method$Pack$open.invoke(pack)); + } + Map> recipes = new HashMap<>(); + boolean hasDisabledAny = !Config.disabledVanillaRecipes().isEmpty(); + try (AutoCloseable resourceManager = (AutoCloseable) CoreReflections.constructor$MultiPackResourceManager.newInstance(CoreReflections.instance$PackType$SERVER_DATA, packResources)) { + Map scannedResources = (Map) CoreReflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); + for (Map.Entry entry : scannedResources.entrySet()) { + Key id = extractKeyFromResourceLocation(entry.getKey().toString()); + if (Config.disableAllVanillaRecipes()) { + this.recipesToUnregister.add(new Pair<>(id, false)); + continue; + } + if (hasDisabledAny && Config.disabledVanillaRecipes().contains(id)) { + this.recipesToUnregister.add(new Pair<>(id, false)); + continue; + } + Reader reader = (Reader) CoreReflections.method$Resource$openAsReader.invoke(entry.getValue()); + JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); + Key serializerType = Key.of(jsonObject.get("type").getAsString()); + RecipeSerializer> serializer = (RecipeSerializer>) BuiltInRegistries.RECIPE_SERIALIZER.getValue(serializerType); + if (serializer == null) { + continue; + } + try { + Recipe recipe = serializer.readJson(id, jsonObject); + recipes.put(id, recipe); + } catch (Exception e) { + this.plugin.logger().warn("Failed to load data pack recipe " + id + ". Json: " + jsonObject, e); + } + } + } catch (Exception e) { + this.plugin.logger().warn("Unknown error occurred when loading data pack recipes", e); + } + return recipes; + } + + private Key extractKeyFromResourceLocation(String input) { + int prefixEndIndex = input.indexOf(':'); + String prefix = input.substring(0, prefixEndIndex); + int lastSlashIndex = input.lastIndexOf('/'); + int lastDotIndex = input.lastIndexOf('.'); + String fileName = input.substring(lastSlashIndex + 1, lastDotIndex); + return Key.of(prefix, fileName); + } + + @Override + public void runDelayedSyncTasks() { + if (!Config.enableRecipeSystem()) return; + + // 卸载掉需要卸载的配方(禁用的原版配方+注册的自定义配方) + for (Pair pair : this.recipesToUnregister) { + unregisterPlatformRecipeMainThread(pair.left(), pair.right()); + } + // 注册新的配方 + for (Recipe recipe : this.byId.values()) { + registerPlatformRecipeMainThread(recipe); + } + + try { + // give flags back on 1.21.2+ + if (VersionHelper.isOrAbove1_21_2() && this.stolenFeatureFlagSet != null) { + CoreReflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager(), this.stolenFeatureFlagSet); + this.stolenFeatureFlagSet = null; + } + + // refresh recipes + if (VersionHelper.isOrAbove1_21_2()) { + CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager()); + } + + // send to players + CoreReflections.method$DedicatedPlayerList$reloadRecipes.invoke(CraftBukkitReflections.field$CraftServer$playerList.get(Bukkit.getServer())); + + // now we need to remove the fake `exact` choices + if (VersionHelper.isOrAbove1_21_4()) { + for (Object ingredient : MODIFIED_INGREDIENTS) { + CoreReflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null); + } + } else if (VersionHelper.isOrAbove1_21_2()) { + for (Object ingredient : MODIFIED_INGREDIENTS) { + CoreReflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null); + } + } + + // clear cache + MODIFIED_INGREDIENTS.clear(); + } catch (Exception e) { + this.plugin.logger().warn("Failed to run delayed recipe tasks", e); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java deleted file mode 100644 index 6fb03e8ec..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.momirealms.craftengine.bukkit.item.recipe; - -import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.ItemStackUtils; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.ItemManager; -import net.momirealms.craftengine.core.item.recipe.Recipe; -import net.momirealms.craftengine.core.item.recipe.RecipeType; -import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; -import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.util.Key; -import org.bukkit.block.Crafter; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.CrafterCraftEvent; -import org.bukkit.inventory.CraftingRecipe; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; - -import java.util.ArrayList; -import java.util.List; - -public class CrafterEventListener implements Listener { - private final ItemManager itemManager; - private final BukkitRecipeManager recipeManager; - private final BukkitCraftEngine plugin; - - public CrafterEventListener(BukkitCraftEngine plugin, BukkitRecipeManager recipeManager, ItemManager itemManager) { - this.itemManager = itemManager; - this.recipeManager = recipeManager; - this.plugin = plugin; - } - - @EventHandler - public void onCrafting(CrafterCraftEvent event) { - if (!Config.enableRecipeSystem()) return; - CraftingRecipe recipe = event.getRecipe(); - if (!(event.getBlock().getState() instanceof Crafter crafter)) { - return; - } - - Key recipeId = Key.of(recipe.getKey().namespace(), recipe.getKey().value()); - boolean isCustom = this.recipeManager.isCustomRecipe(recipeId); - - // Maybe it's recipe from other plugins, then we ignore it - if (!isCustom) { - return; - } - - Inventory inventory = crafter.getInventory(); - ItemStack[] ingredients = inventory.getStorageContents(); - - List> uniqueIdItems = new ArrayList<>(); - for (ItemStack itemStack : ingredients) { - if (ItemStackUtils.isEmpty(itemStack)) { - uniqueIdItems.add(this.itemManager.uniqueEmptyItem()); - } else { - Item wrappedItem = this.itemManager.wrap(itemStack); - uniqueIdItems.add(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); - } - } - - CraftingInput input; - if (ingredients.length == 9) { - input = CraftingInput.of(3, 3, uniqueIdItems); - } else if (ingredients.length == 4) { - input = CraftingInput.of(2, 2, uniqueIdItems); - } else { - return; - } - - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.CRAFTING, input); - if (ceRecipe != null) { - event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY)); - return; - } - // clear result if not met - event.setCancelled(true); - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index ceb1036ee..8c2d8f75a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -4,12 +4,9 @@ import com.destroystokyo.paper.event.inventory.PrepareResultEvent; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.ComponentTypes; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.injector.RecipeInjector; 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.MRecipeTypes; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.InventoryUtils; @@ -28,21 +25,14 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.util.*; import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.Campfire; -import org.bukkit.block.Furnace; -import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.*; import org.bukkit.event.inventory.*; import org.bukkit.event.inventory.ClickType; -import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.*; import org.bukkit.inventory.view.AnvilView; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -74,7 +64,7 @@ public class RecipeEventListener implements Listener { ItemStack item = event.getCurrentItem(); if (ItemStackUtils.isEmpty(item)) return; if (ItemStackUtils.isEmpty(fuelStack)) { - SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(item)); + SingleItemInput input = new SingleItemInput<>(ItemStackUtils.getUniqueIdItem(item)); RecipeType recipeType; if (furnaceInventory.getType() == InventoryType.FURNACE) { recipeType = RecipeType.SMELTING; @@ -258,166 +248,9 @@ public class RecipeEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onFurnaceInventoryOpen(InventoryOpenEvent event) { - if (!Config.enableRecipeSystem()) return; - if (!(event.getInventory() instanceof FurnaceInventory furnaceInventory)) { - return; - } - Furnace furnace = furnaceInventory.getHolder(); - try { - Object blockEntity = CraftBukkitReflections.field$CraftBlockEntityState$tileEntity.get(furnace); - RecipeInjector.injectCookingBlockEntity(blockEntity); - } catch (Exception e) { - this.plugin.logger().warn("Failed to inject cooking block entity", e); - } - } - - // for 1.20.1-1.21.1 - @EventHandler(ignoreCancelled = true) - public void onBlockIgnite(BlockIgniteEvent event) { - if (!Config.enableRecipeSystem()) return; - if (VersionHelper.isOrAbove1_21_2()) return; - Block block = event.getBlock(); - Material material = block.getType(); - if (material == Material.CAMPFIRE) { - if (block.getState() instanceof Campfire campfire) { - try { - Object blockEntity = CraftBukkitReflections.field$CraftBlockEntityState$tileEntity.get(campfire); - RecipeInjector.injectCookingBlockEntity(blockEntity); - } catch (Exception e) { - this.plugin.logger().warn("Failed to inject cooking block entity", e); - } - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onPlaceBlock(BlockPlaceEvent event) { - if (!Config.enableRecipeSystem()) return; - Block block = event.getBlock(); - Material material = block.getType(); - if (material == Material.FURNACE || material == Material.BLAST_FURNACE || material == Material.SMOKER) { - if (block.getState() instanceof Furnace furnace) { - try { - Object blockEntity = CraftBukkitReflections.field$CraftBlockEntityState$tileEntity.get(furnace); - RecipeInjector.injectCookingBlockEntity(blockEntity); - } catch (Exception e) { - plugin.logger().warn("Failed to inject cooking block entity", e); - } - } - } else if (!VersionHelper.isOrAbove1_21_2() && material == Material.CAMPFIRE) { - if (block.getState() instanceof Campfire campfire) { - try { - Object blockEntity = CraftBukkitReflections.field$CraftBlockEntityState$tileEntity.get(campfire); - RecipeInjector.injectCookingBlockEntity(blockEntity); - } catch (Exception e) { - this.plugin.logger().warn("Failed to inject cooking block entity", e); - } - } - } - } - - // for 1.21.2+ - @EventHandler(ignoreCancelled = true) - public void onPutItemOnCampfire(PlayerInteractEvent event) { - if (!Config.enableRecipeSystem()) return; - if (!VersionHelper.isOrAbove1_21_2()) return; - if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; - Block clicked = event.getClickedBlock(); - if (clicked == null) return; - Material type = clicked.getType(); - if (type != Material.CAMPFIRE && type != Material.SOUL_CAMPFIRE) return; - if (clicked.getState() instanceof Campfire campfire) { - try { - Object blockEntity = CraftBukkitReflections.field$CraftBlockEntityState$tileEntity.get(campfire); - RecipeInjector.injectCookingBlockEntity(blockEntity); - } catch (Exception e) { - this.plugin.logger().warn("Failed to inject cooking block entity", e); - } - } - - ItemStack itemStack = event.getItem(); - if (ItemStackUtils.isEmpty(itemStack)) return; - try { - @SuppressWarnings("unchecked") - Optional optionalMCRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor( - BukkitRecipeManager.minecraftRecipeManager(), - MRecipeTypes.CAMPFIRE_COOKING, - CoreReflections.constructor$SingleRecipeInput.newInstance(FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)), - FastNMS.INSTANCE.field$CraftWorld$ServerLevel(event.getPlayer().getWorld()), - null - ); - if (optionalMCRecipe.isEmpty()) { - return; - } - SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeType.CAMPFIRE_COOKING, input); - if (ceRecipe == null) { - event.setCancelled(true); - } - } catch (Exception e) { - this.plugin.logger().warn("Failed to handle interact campfire", e); - } - } - - // for 1.21.2+ - @SuppressWarnings("UnstableApiUsage") - @EventHandler(ignoreCancelled = true) - public void onCampfireCook(CampfireStartEvent event) { - if (!Config.enableRecipeSystem()) return; - if (!VersionHelper.isOrAbove1_21_2()) return; - CampfireRecipe recipe = event.getRecipe(); - Key recipeId = new Key(recipe.getKey().namespace(), recipe.getKey().value()); - - boolean isCustom = this.recipeManager.isCustomRecipe(recipeId); - if (!isCustom) { - return; - } - - ItemStack itemStack = event.getSource(); - SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeType.CAMPFIRE_COOKING, input); - if (ceRecipe == null) { - event.setTotalCookTime(Integer.MAX_VALUE); - return; - } - - event.setTotalCookTime(ceRecipe.cookingTime()); - } - - // for 1.21.2+ - @EventHandler(ignoreCancelled = true) - public void onCampfireCook(BlockCookEvent event) { - if (!Config.enableRecipeSystem()) return; - if (!VersionHelper.isOrAbove1_21_2()) return; - Material type = event.getBlock().getType(); - if (type != Material.CAMPFIRE && type != Material.SOUL_CAMPFIRE) return; - CampfireRecipe recipe = (CampfireRecipe) event.getRecipe(); - if (recipe == null) return; - - Key recipeId = new Key(recipe.getKey().namespace(), recipe.getKey().value()); - - boolean isCustom = this.recipeManager.isCustomRecipe(recipeId); - if (!isCustom) { - return; - } - - ItemStack itemStack = event.getSource(); - SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeType.CAMPFIRE_COOKING, input); - if (ceRecipe == null) { - event.setCancelled(true); - return; - } - - event.setResult(ceRecipe.result(ItemBuildContext.EMPTY)); - } - // Paper only @EventHandler public void onPrepareResult(PrepareResultEvent event) { -// if (!ConfigManager.enableRecipeSystem()) return; if (event.getInventory() instanceof CartographyInventory cartographyInventory) { if (ItemStackUtils.hasCustomItem(cartographyInventory.getStorageContents())) { event.setResult(new ItemStack(Material.AIR)); @@ -745,98 +578,35 @@ public class RecipeEventListener implements Listener { return new Pair<>(first, second); } - // 不是完美的解决方案,仍然需要更多的探讨 - // TODO 生成类代理掉ResultSlot,并注入menu的slots对象,修改掉onTake方法 - // TODO 对于耐久度降低的配方,应该注册special recipe? - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onCraft(CraftItemEvent event) { - org.bukkit.inventory.Recipe recipe = event.getRecipe(); - if (!(recipe instanceof ShapelessRecipe) && !(recipe instanceof ShapedRecipe)) return; - HumanEntity humanEntity = event.getWhoClicked(); - if (!(humanEntity instanceof Player player)) return; - CraftingInventory inventory = event.getInventory(); - ItemStack result = inventory.getResult(); - if (result == null) return; - ItemStack[] usedItems = inventory.getMatrix(); - ItemStack[] replacements = new ItemStack[usedItems.length]; - boolean hasReplacement = false; - for (int i = 0; i < usedItems.length; i++) { - ItemStack usedItem = usedItems[i]; - if (ItemStackUtils.isEmpty(usedItem)) continue; - if (usedItem.getAmount() != 1) continue; - Item wrapped = BukkitItemManager.instance().wrap(usedItem); - if (ItemUtils.isEmpty(wrapped)) continue; - Optional> optionalCustomItem = wrapped.getCustomItem(); - if (optionalCustomItem.isPresent()) { - CustomItem customItem = optionalCustomItem.get(); - Key remainingItem = customItem.settings().craftRemainder(); - if (remainingItem != null) { - replacements[i] = BukkitItemManager.instance().buildItemStack(remainingItem, this.plugin.adapt(player)); - hasReplacement = true; - } - } - } - if (!hasReplacement) return; - Runnable delayedTask = () -> { - for (int i = 0; i < replacements.length; i++) { - if (replacements[i] == null) continue; - inventory.setItem(i + 1, replacements[i]); - } - }; - if (VersionHelper.isFolia()) { - player.getScheduler().run(this.plugin.javaPlugin(), (t) -> delayedTask.run(), () -> {}); - } else { - this.plugin.scheduler().sync().runDelayed(delayedTask); - } - } - @EventHandler(ignoreCancelled = true) public void onCraftingRecipe(PrepareItemCraftEvent event) { if (!Config.enableRecipeSystem()) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); - - // we only handle shaped and shapeless recipes - boolean shapeless = recipe instanceof ShapelessRecipe; - boolean shaped = recipe instanceof ShapedRecipe; - if (!shaped && !shapeless) return; - - CraftingRecipe craftingRecipe = (CraftingRecipe) recipe; + if (!(recipe instanceof CraftingRecipe craftingRecipe)) return; Key recipeId = Key.of(craftingRecipe.getKey().namespace(), craftingRecipe.getKey().value()); - - boolean isCustom = this.recipeManager.isCustomRecipe(recipeId); - // Maybe it's recipe from other plugins, then we ignore it - if (!isCustom) { + Optional> optionalRecipe = this.recipeManager.recipeById(recipeId); + // 也许是其他插件注册的配方,直接无视 + if (optionalRecipe.isEmpty()) { return; } - CraftingInventory inventory = event.getInventory(); + if (!(optionalRecipe.get() instanceof CustomCraftingTableRecipe craftingTableRecipe)) { + inventory.setResult(null); + return; + } CraftingInput input = getCraftingInput(inventory); if (input == null) return; - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); BukkitServerPlayer serverPlayer = this.plugin.adapt(player); - - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.CRAFTING, input, recipeId); - if (ceRecipe != null) { - inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); - serverPlayer.setLastUsedRecipe(ceRecipe.id()); - if (!ceRecipe.id().equals(recipeId)) { - correctCraftingRecipeUsed(inventory, ceRecipe); - } - return; - } - // clear result if not met - inventory.setResult(null); + inventory.setResult(craftingTableRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); } private CraftingInput getCraftingInput(CraftingInventory inventory) { ItemStack[] ingredients = inventory.getMatrix(); - List> uniqueIdItems = new ArrayList<>(); for (ItemStack itemStack : ingredients) { - uniqueIdItems.add(getUniqueIdItem(itemStack)); + uniqueIdItems.add(ItemStackUtils.getUniqueIdItem(itemStack)); } - CraftingInput input; if (ingredients.length == 9) { input = CraftingInput.of(3, 3, uniqueIdItems); @@ -848,17 +618,6 @@ public class RecipeEventListener implements Listener { return input; } - private void correctCraftingRecipeUsed(CraftingInventory inventory, Recipe recipe) { - Object holderOrRecipe = this.recipeManager.nmsRecipeHolderByRecipe(recipe); - if (holderOrRecipe == null) { - return; - } - Object resultInventory = FastNMS.INSTANCE.method$CraftInventoryCrafting$getResultInventory(inventory); - FastNMS.INSTANCE.method$ResultContainer$setRecipeUsed(resultInventory, holderOrRecipe); - Object matrixInventory = FastNMS.INSTANCE.method$CraftInventoryCrafting$getMatrixInventory(inventory); - FastNMS.INSTANCE.method$CraftingContainer$setCurrentRecipe(matrixInventory, holderOrRecipe); - } - @EventHandler(ignoreCancelled = true) public void onSmithingTrim(PrepareSmithingEvent event) { SmithingInventory inventory = event.getInventory(); @@ -880,31 +639,17 @@ public class RecipeEventListener implements Listener { } Key recipeId = Key.of(recipe.getKey().namespace(), recipe.getKey().value()); - boolean isCustom = this.recipeManager.isCustomRecipe(recipeId); - // Maybe it's recipe from other plugins, then we ignore it - if (!isCustom) { + Optional> optionalRecipe = this.recipeManager.recipeById(recipeId); + if (optionalRecipe.isEmpty()) { return; } - - SmithingInput input = new SmithingInput<>( - getUniqueIdItem(inventory.getInputEquipment()), - getUniqueIdItem(inventory.getInputTemplate()), - getUniqueIdItem(inventory.getInputMineral()) - ); - - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.SMITHING, input, recipeId); - if (ceRecipe == null) { + if (!(optionalRecipe.get() instanceof CustomSmithingTrimRecipe smithingTrimRecipe)) { event.setResult(null); return; } - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - CustomSmithingTrimRecipe trimRecipe = (CustomSmithingTrimRecipe) ceRecipe; - ItemStack result = trimRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); + ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); event.setResult(result); - if (!ceRecipe.id().equals(recipeId)) { - correctSmithingRecipeUsed(inventory, ceRecipe); - } } @EventHandler(ignoreCancelled = true) @@ -912,59 +657,25 @@ public class RecipeEventListener implements Listener { if (!Config.enableRecipeSystem()) return; SmithingInventory inventory = event.getInventory(); if (!(inventory.getRecipe() instanceof SmithingTransformRecipe recipe)) return; - Key recipeId = Key.of(recipe.getKey().namespace(), recipe.getKey().value()); - boolean isCustom = this.recipeManager.isCustomRecipe(recipeId); - // Maybe it's recipe from other plugins, then we ignore it - if (!isCustom) { + Optional> optionalRecipe = this.recipeManager.recipeById(recipeId); + if (optionalRecipe.isEmpty()) { return; } - - ItemStack base = inventory.getInputEquipment(); - ItemStack template = inventory.getInputTemplate(); - ItemStack addition = inventory.getInputMineral(); - - SmithingInput input = new SmithingInput<>( - getUniqueIdItem(base), - getUniqueIdItem(template), - getUniqueIdItem(addition) - ); - - Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeType.SMITHING, input, recipeId); - if (ceRecipe == null) { + if (!(optionalRecipe.get() instanceof CustomSmithingTransformRecipe smithingTransformRecipe)) { event.setResult(null); return; } - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - - CustomSmithingTransformRecipe transformRecipe = (CustomSmithingTransformRecipe) ceRecipe; - ItemStack processed = transformRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); + ItemStack processed = smithingTransformRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); event.setResult(processed); - if (!ceRecipe.id().equals(recipeId)) { - correctSmithingRecipeUsed(inventory, ceRecipe); - } } - private void correctSmithingRecipeUsed(SmithingInventory inventory, Recipe recipe) { - Object holderOrRecipe = this.recipeManager.nmsRecipeHolderByRecipe(recipe); - if (holderOrRecipe == null) { - return; - } - try { - Object resultInventory = CraftBukkitReflections.field$CraftResultInventory$resultInventory.get(inventory); - CoreReflections.field$ResultContainer$recipeUsed.set(resultInventory, holderOrRecipe); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to correct used recipe", e); - } - } - - private UniqueIdItem getUniqueIdItem(@Nullable ItemStack itemStack) { - if (ItemStackUtils.isEmpty(itemStack)) { - return this.itemManager.uniqueEmptyItem(); - } else { - Item wrappedItem = this.itemManager.wrap(itemStack); - return new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem); - } + private SmithingInput getSmithingInput(SmithingInventory inventory) { + return new SmithingInput<>( + ItemStackUtils.getUniqueIdItem(inventory.getInputEquipment()), + ItemStackUtils.getUniqueIdItem(inventory.getInputTemplate()), + ItemStackUtils.getUniqueIdItem(inventory.getInputMineral()) + ); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index 7ae11cc4f..bad128c87 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -60,28 +60,12 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { @Override public void unload() { super.unload(); - if (ReloadCommand.RELOAD_PACK_FLAG) { - if (VersionHelper.isOrAbove1_20_2()) { - this.resetServerSettings(); - } - } } @Override public void disable() { super.disable(); HandlerList.unregisterAll(this); - this.resetServerSettings(); - } - - public void resetServerSettings() { - try { - Object settings = CoreReflections.field$DedicatedServer$settings.get(CoreReflections.method$MinecraftServer$getServer.invoke(null)); - Object properties = CoreReflections.field$DedicatedServerSettings$properties.get(settings); - CoreReflections.field$DedicatedServerProperties$serverResourcePackInfo.set(properties, Optional.empty()); - } catch (Exception e) { - this.plugin.logger().warn("Failed to reset resource pack settings", e); - } } @EventHandler(priority = EventPriority.MONITOR) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 63ad89c4b..623bdf0e2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -6,32 +6,22 @@ import it.unimi.dsi.fastutil.ints.IntList; import net.bytebuddy.ByteBuddy; import net.bytebuddy.ClassFileVersion; import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; -import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.bind.annotation.AllArguments; import net.bytebuddy.implementation.bind.annotation.RuntimeType; -import net.bytebuddy.implementation.bind.annotation.This; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatchers; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.ComponentTypes; -import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRecipeTypes; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.data.FireworkExplosion; -import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe; -import net.momirealms.craftengine.core.item.recipe.RecipeType; -import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; -import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.util.*; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -46,43 +36,13 @@ import java.util.function.Function; import java.util.function.Predicate; public class RecipeInjector { - private static Class clazz$InjectedCacheChecker; private static Class clazz$InjectedArmorDyeRecipe; private static Class clazz$InjectedRepairItemRecipe; private static Class clazz$InjectedFireworkStarFadeRecipe; public static void init() { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); - clazz$InjectedCacheChecker = byteBuddy - .subclass(Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) - .name("net.momirealms.craftengine.bukkit.entity.InjectedCacheChecker") - .implement(CoreReflections.clazz$RecipeManager$CachedCheck) - .implement(InjectedCacheCheck.class) - .defineField("recipeType", Object.class, Visibility.PUBLIC) - .method(ElementMatchers.named("recipeType")) - .intercept(FieldAccessor.ofField("recipeType")) - .defineField("customRecipeType", RecipeType.class, Visibility.PUBLIC) - .method(ElementMatchers.named("customRecipeType")) - .intercept(FieldAccessor.ofField("customRecipeType")) - .defineField("lastRecipe", Object.class, Visibility.PUBLIC) - .method(ElementMatchers.named("lastRecipe")) - .intercept(FieldAccessor.ofField("lastRecipe")) - .defineField("lastCustomRecipe", Key.class, Visibility.PUBLIC) - .method(ElementMatchers.named("lastCustomRecipe")) - .intercept(FieldAccessor.ofField("lastCustomRecipe")) - .method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a"))) - .intercept(MethodDelegation.to( - VersionHelper.isOrAbove1_21_2() ? - GetRecipeForMethodInterceptor1_21_2.INSTANCE : - (VersionHelper.isOrAbove1_21() ? - GetRecipeForMethodInterceptor1_21.INSTANCE : - VersionHelper.isOrAbove1_20_5() ? - GetRecipeForMethodInterceptor1_20_5.INSTANCE : - GetRecipeForMethodInterceptor1_20.INSTANCE) - )) - .make() - .load(RecipeInjector.class.getClassLoader()) - .getLoaded(); + ElementMatcher.Junction matches = (VersionHelper.isOrAbove1_21() ? ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$Level) : ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$Level) @@ -151,35 +111,6 @@ public class RecipeInjector { } } - public static void injectCookingBlockEntity(Object entity) throws ReflectiveOperationException { - if (CoreReflections.clazz$AbstractFurnaceBlockEntity.isInstance(entity)) { - Object quickCheck = CoreReflections.field$AbstractFurnaceBlockEntity$quickCheck.get(entity); - if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected - Object recipeType = FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$recipeType(entity); - InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); - if (recipeType == MRecipeTypes.SMELTING) { - injectedChecker.customRecipeType(RecipeType.SMELTING); - injectedChecker.recipeType(MRecipeTypes.SMELTING); - } else if (recipeType == MRecipeTypes.BLASTING) { - injectedChecker.customRecipeType(RecipeType.BLASTING); - injectedChecker.recipeType(MRecipeTypes.BLASTING); - } else if (recipeType == MRecipeTypes.SMOKING) { - injectedChecker.customRecipeType(RecipeType.SMOKING); - injectedChecker.recipeType(MRecipeTypes.SMOKING); - } else { - throw new IllegalStateException("RecipeType " + recipeType + " not supported"); - } - CoreReflections.field$AbstractFurnaceBlockEntity$quickCheck.set(entity, injectedChecker); - } else if (!VersionHelper.isOrAbove1_21_2() && CoreReflections.clazz$CampfireBlockEntity.isInstance(entity)) { - Object quickCheck = CoreReflections.field$CampfireBlockEntity$quickCheck.get(entity); - if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected - InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); - injectedChecker.customRecipeType(RecipeType.CAMPFIRE_COOKING); - injectedChecker.recipeType(MRecipeTypes.CAMPFIRE_COOKING); - CoreReflections.field$CampfireBlockEntity$quickCheck.set(entity, injectedChecker); - } - } - private static final Function INGREDIENT_SIZE_GETTER = VersionHelper.isOrAbove1_21() ? FastNMS.INSTANCE::method$CraftingInput$size : @@ -471,185 +402,4 @@ public class RecipeInjector { private static boolean isVanillaDyeItem(Item item) { return CoreReflections.clazz$DyeItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject())); } - - @SuppressWarnings("DuplicatedCode") - public static class GetRecipeForMethodInterceptor1_20 { - public static final GetRecipeForMethodInterceptor1_20 INSTANCE = new GetRecipeForMethodInterceptor1_20(); - - @SuppressWarnings("unchecked") - @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) { - InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); - Optional> optionalRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); - if (optionalRecipe.isEmpty()) { - return Optional.empty(); - } - - Pair resourceLocationAndRecipe = optionalRecipe.get(); - Object rawRecipeResourceLocation = resourceLocationAndRecipe.getFirst(); - Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - - boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); - if (!isCustom) { - injectedCacheCheck.lastRecipe(rawRecipeResourceLocation); - return Optional.of(resourceLocationAndRecipe.getSecond()); - } - - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror( - injectedCacheCheck.recipeType() == MRecipeTypes.CAMPFIRE_COOKING ? - FastNMS.INSTANCE.field$SimpleContainer$items(args[0]).getFirst() : - FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$getItem(args[0], 0) - ); - - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); - CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); - if (ceRecipe == null) { - return Optional.empty(); - } - - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - if (!ceRecipe.id().equals(rawRecipeKey)) { - injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id())); - } - return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); - } - } - - @SuppressWarnings("DuplicatedCode") - public static class GetRecipeForMethodInterceptor1_20_5 { - public static final GetRecipeForMethodInterceptor1_20_5 INSTANCE = new GetRecipeForMethodInterceptor1_20_5(); - - @SuppressWarnings("unchecked") - @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) { - InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); - if (optionalRecipe.isEmpty()) { - return Optional.empty(); - } - - Object rawRecipeHolder = optionalRecipe.get(); - Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$RecipeHolder$id(rawRecipeHolder); - Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); - - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror( - injectedCacheCheck.recipeType() == MRecipeTypes.CAMPFIRE_COOKING ? - FastNMS.INSTANCE.field$SimpleContainer$items(args[0]).getFirst() : - FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$getItem(args[0], 0) - ); - - boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); - if (!isCustom) { - injectedCacheCheck.lastRecipe(rawRecipeResourceLocation); - return optionalRecipe; - } - - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); - CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); - if (ceRecipe == null) { - return Optional.empty(); - } - - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - if (!ceRecipe.id().equals(rawRecipeKey)) { - injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id())); - } - return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); - } - } - - @SuppressWarnings("DuplicatedCode") - public static class GetRecipeForMethodInterceptor1_21 { - public static final GetRecipeForMethodInterceptor1_21 INSTANCE = new GetRecipeForMethodInterceptor1_21(); - - @SuppressWarnings("unchecked") - @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) { - InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); - if (optionalRecipe.isEmpty()) { - return Optional.empty(); - } - - Object rawRecipeHolder = optionalRecipe.get(); - Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$RecipeHolder$id(rawRecipeHolder); - Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); - - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); - if (!isCustom) { - injectedCacheCheck.lastRecipe(rawRecipeResourceLocation); - return optionalRecipe; - } - - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0])); - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); - CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); - if (ceRecipe == null) { - return Optional.empty(); - } - - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - if (!ceRecipe.id().equals(rawRecipeKey)) { - injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id())); - } - return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); - } - } - - @SuppressWarnings("DuplicatedCode") - public static class GetRecipeForMethodInterceptor1_21_2 { - public static final GetRecipeForMethodInterceptor1_21_2 INSTANCE = new GetRecipeForMethodInterceptor1_21_2(); - - @SuppressWarnings("unchecked") - @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) { - InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object lastRecipeResourceKey = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.minecraftRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceKey); - if (optionalRecipe.isEmpty()) { - return Optional.empty(); - } - - // 获取配方的基础信息 - Object recipeHolder = optionalRecipe.get(); - Object rawRecipeResourceKey = FastNMS.INSTANCE.field$RecipeHolder$id(recipeHolder); - Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$ResourceKey$location(rawRecipeResourceKey); - Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); - - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - // 来自其他插件注册的自定义配方 - boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); - if (!isCustom) { - injectedCacheCheck.lastRecipe(rawRecipeResourceKey); - return optionalRecipe; - } - - // 获取唯一内存地址id - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0])); - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); - CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); - // 这个ce配方并不存在,那么应该返回空 - if (ceRecipe == null) { - return Optional.empty(); - } - - // 记录上一次使用的配方(ce) - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - // 更新上一次使用的配方(nms) - if (!ceRecipe.id().equals(rawRecipeKey)) { - injectedCacheCheck.lastRecipe(FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(ceRecipe.id()))); - } - return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); - } - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index cfa1bf880..291e542c3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -128,7 +128,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.plugin.javaPlugin().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL); // Inject server channel try { - Object server = CoreReflections.method$MinecraftServer$getServer.invoke(null); + Object server = FastNMS.INSTANCE.method$MinecraftServer$getServer(); Object serverConnection = CoreReflections.field$MinecraftServer$connection.get(server); @SuppressWarnings("unchecked") List channels = (List) CoreReflections.field$ServerConnectionListener$channels.get(serverConnection); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 125a9a8cf..4877f0aa3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -2849,10 +2849,6 @@ public final class CoreReflections { ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("server.MinecraftServer")) ); - public static final Method method$MinecraftServer$getServer = requireNonNull( - ReflectionUtils.getMethod(clazz$MinecraftServer, new String[] { "getServer" }) - ); - public static final Field field$MinecraftServer$registries = requireNonNull( ReflectionUtils.getDeclaredField(clazz$MinecraftServer, clazz$LayeredRegistryAccess, 0) ); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 2ef53cd94..fd6156d23 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -93,8 +93,6 @@ public class BukkitServerPlayer extends Player { // for client visual sync private int resentSoundTick; private int resentSwingTick; - // cache used recipe - private Key lastUsedRecipe = null; // has fabric client mod or not private boolean hasClientMod = false; // cache if player can break blocks @@ -885,14 +883,6 @@ public class BukkitServerPlayer extends Player { return resentSwingTick == gameTicks(); } - public Key lastUsedRecipe() { - return lastUsedRecipe; - } - - public void setLastUsedRecipe(Key lastUsedRecipe) { - this.lastUsedRecipe = lastUsedRecipe; - } - public boolean clientModEnabled() { return this.hasClientMod; } 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 2bbe31a7a..ec33bb09f 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 @@ -129,15 +129,11 @@ public class InteractUtils { }); registerInteraction(BlockKeys.SOUL_CAMPFIRE, (player, item, blockState, result) -> { if (!Config.enableRecipeSystem()) return false; - return BukkitRecipeManager.instance().recipeByInput(RecipeType.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( - item.recipeIngredientId(), item - ))) != null; + return BukkitRecipeManager.instance().recipeByInput(RecipeType.CAMPFIRE_COOKING, new SingleItemInput<>(UniqueIdItem.of(item))) != null; }); registerInteraction(BlockKeys.CAMPFIRE, (player, item, blockState, result) -> { if (!Config.enableRecipeSystem()) return false; - return BukkitRecipeManager.instance().recipeByInput(RecipeType.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( - item.recipeIngredientId(), item - ))) != null; + return BukkitRecipeManager.instance().recipeByInput(RecipeType.CAMPFIRE_COOKING, new SingleItemInput<>(UniqueIdItem.of(item))) != null; }); registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> { if (!(blockState instanceof ChiseledBookshelf chiseledBookshelf)) return false; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java index 1ade133c7..bbebf2a97 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java @@ -3,11 +3,14 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; -public class ItemStackUtils { +public final class ItemStackUtils { private ItemStackUtils() {} @@ -43,4 +46,9 @@ public class ItemStackUtils { return FastNMS.INSTANCE.method$CraftItemStack$asCraftCopy(itemStack); } } + + public static UniqueIdItem getUniqueIdItem(@Nullable ItemStack itemStack) { + Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); + return UniqueIdItem.of(wrappedItem); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java index 8fed8c247..ca67f6b6b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java @@ -1,50 +1,7 @@ package net.momirealms.craftengine.bukkit.util; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.VersionHelper; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - public class RecipeUtils { private RecipeUtils() {} - @SuppressWarnings("unchecked") - public static List getIngredientsFromShapedRecipe(Object recipe) { - List ingredients = new ArrayList<>(); - try { - if (VersionHelper.isOrAbove1_20_3()) { - Object pattern = CoreReflections.field$1_20_3$ShapedRecipe$pattern.get(recipe); - if (VersionHelper.isOrAbove1_21_2()) { - List> optionals = (List>) CoreReflections.field$ShapedRecipePattern$ingredients1_21_2.get(pattern); - for (Optional optional : optionals) { - optional.ifPresent(ingredients::add); - } - } else { - List objectList = (List) CoreReflections.field$ShapedRecipePattern$ingredients1_20_3.get(pattern); - for (Object object : objectList) { - Object[] values = (Object[]) CoreReflections.field$Ingredient$values.get(object); - // is empty or not - if (values.length != 0) { - ingredients.add(object); - } - } - } - } else { - List objectList = (List) CoreReflections.field$1_20_1$ShapedRecipe$recipeItems.get(recipe); - for (Object object : objectList) { - Object[] values = (Object[]) CoreReflections.field$Ingredient$values.get(object); - if (values.length != 0) { - ingredients.add(object); - } - } - } - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to get ingredients from shaped recipe", e); - } - return ingredients; - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index bd04de0e4..e4d090bad 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -403,13 +403,6 @@ public class BukkitWorldManager implements WorldManager, Listener { (injected) -> sections[finalI] = injected); } } - if (Config.enableRecipeSystem()) { - @SuppressWarnings("unchecked") - Map blockEntities = (Map) FastNMS.INSTANCE.field$ChunkAccess$blockEntities(levelChunk); - for (Object blockEntity : blockEntities.values()) { - RecipeInjector.injectCookingBlockEntity(blockEntity); - } - } } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to restore chunk at " + chunk.getX() + " " + chunk.getZ(), e); return; diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 8f0f5a79a..8a428d817 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -143,6 +143,8 @@ warning.config.recipe.smithing_trim.missing_addition: "Issue found in fi warning.config.recipe.smithing_trim.missing_pattern: "Issue found in file - The smithing trim recipe '' is missing the required 'pattern' argument." warning.config.recipe.brewing.missing_container: "Issue found in file - The brewing recipe '' is missing the required 'container' argument." warning.config.recipe.brewing.missing_ingredient: "Issue found in file - The brewing recipe '' is missing the required 'ingredient' argument." +warning.config.recipe.result.post_processor.missing_type: "Issue found in file - The recipe '' is missing the required 'type' argument for result post processors." +warning.config.recipe.result.post_processor.invalid_type: "Issue found in file - The recipe '' is using an invalid result post processor type ''." warning.config.i18n.unknown_locale: "Issue found in file - Unknown locale ''." warning.config.template.duplicate: "Issue found in file - Duplicated template ''. Please check if there is the same configuration in other files." warning.config.template.invalid: "Issue found in file - The config '' is using an invalid template ''." diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java index 1cfb119f9..8abe2a871 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java @@ -464,7 +464,7 @@ public class BlockSettings { LazyReference> correctTools = LazyReference.lazyReference(() -> { Set ids = new HashSet<>(); for (String tool : tools) { - if (tool.charAt(0) == '#') ids.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(tool.substring(1))).stream().map(UniqueKey::key).toList()); + if (tool.charAt(0) == '#') ids.addAll(CraftEngine.instance().itemManager().itemIdsByTag(Key.of(tool.substring(1))).stream().map(UniqueKey::key).toList()); else ids.add(Key.of(tool)); } return ids; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index db56a096f..66e6c4d53 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.Optional; public abstract class AbstractCustomItem implements CustomItem { + protected final boolean isVanillaItem; protected final UniqueKey id; protected final Key material; protected final Key clientBoundMaterial; @@ -25,12 +26,13 @@ public abstract class AbstractCustomItem implements CustomItem { protected final Map>> events; @SuppressWarnings("unchecked") - public AbstractCustomItem(UniqueKey id, Key material, Key clientBoundMaterial, + public AbstractCustomItem(boolean isVanillaItem, UniqueKey id, Key material, Key clientBoundMaterial, List behaviors, List> modifiers, List> clientBoundModifiers, ItemSettings settings, Map>> events) { + this.isVanillaItem = isVanillaItem; this.id = id; this.material = material; this.clientBoundMaterial = clientBoundMaterial; @@ -75,6 +77,11 @@ public abstract class AbstractCustomItem implements CustomItem { return this.modifiers; } + @Override + public boolean isVanillaItem() { + return isVanillaItem; + } + @Override public boolean hasClientBoundDataModifier() { return this.clientBoundModifiers.length != 0; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 6cf94134c..77d581dc1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -137,43 +137,31 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl Key id = customItem.id(); if (this.customItems.containsKey(id)) return false; this.customItems.put(id, customItem); - // cache command suggestions - this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); - // totem animations - if (VersionHelper.isOrAbove1_21_2()) { - this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); - } else if (customItem.material().equals(ItemKeys.TOTEM_OF_UNDYING)) { - this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); - } - // tags - Set tags = customItem.settings().tags(); - for (Key tag : tags) { - this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.uniqueId()); + if (!customItem.isVanillaItem()) { + // cache command suggestions + this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); + // totem animations + if (VersionHelper.isOrAbove1_21_2()) { + this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); + } else if (customItem.material().equals(ItemKeys.TOTEM_OF_UNDYING)) { + this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); + } + // tags + Set tags = customItem.settings().tags(); + for (Key tag : tags) { + this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.uniqueId()); + } } return true; } @Override - public List tagToItems(Key tag) { - List items = new ArrayList<>(); - List holders = VANILLA_ITEM_TAGS.get(tag); - if (holders != null) { - items.addAll(holders); - } - List customItems = this.customItemTags.get(tag); - if (customItems != null) { - items.addAll(customItems); - } - return items; - } - - @Override - public List tagToVanillaItems(Key tag) { + public List vanillaItemIdsByTag(Key tag) { return Collections.unmodifiableList(VANILLA_ITEM_TAGS.getOrDefault(tag, List.of())); } @Override - public List tagToCustomItems(Key tag) { + public List customItemIdsByTag(Key tag) { return Collections.unmodifiableList(this.customItemTags.getOrDefault(tag, List.of())); } @@ -415,6 +403,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 构建自定义物品 CustomItem customItem = itemBuilder + .isVanillaItem(isVanillaItem) .behaviors(behaviors) .settings(settings) .events(eventTriggerListMap) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java new file mode 100644 index 000000000..639d8d137 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java @@ -0,0 +1,30 @@ +package net.momirealms.craftengine.core.item; + +import net.momirealms.craftengine.core.util.Key; + +public class CloneableConstantItem implements BuildableItem { + private final Item item; + + private CloneableConstantItem(Item item) { + this.item = item; + } + + public static CloneableConstantItem of(Item item) { + return new CloneableConstantItem<>(item); + } + + @Override + public Key id() { + return this.item.id(); + } + + @Override + public Item buildItem(ItemBuildContext context, int count) { + return this.item.copyWithCount(count); + } + + @Override + public I buildItemStack(ItemBuildContext context, int count) { + return this.item.copyWithCount(count).getItem(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 2ab666cf9..5d0415a30 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -14,6 +14,8 @@ import java.util.Map; public interface CustomItem extends BuildableItem { + boolean isVanillaItem(); + Key id(); UniqueKey uniqueId(); @@ -40,6 +42,8 @@ public interface CustomItem extends BuildableItem { List behaviors(); interface Builder { + Builder isVanillaItem(boolean isVanillaItem); + Builder id(UniqueKey id); Builder clientBoundMaterial(Key clientBoundMaterialKey); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 30c17b8b4..8e61ca095 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Optional; @@ -37,10 +38,13 @@ public interface Item { boolean isBlockItem(); + @Nullable Key id(); + @Nullable Key vanillaId(); + @Nullable UniqueKey recipeIngredientId(); Optional customId(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 9b82c4f3d..e1c18038d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.equipment.Equipment; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.model.ModernItemModel; @@ -53,10 +54,6 @@ public interface ItemManager extends Manageable, ModelGenerator { Collection items(); - Key itemId(T itemStack); - - Key customItemId(T itemStack); - ExternalItemSource getExternalItemSource(String name); boolean registerExternalItemSource(ExternalItemSource externalItemSource); @@ -81,11 +78,16 @@ public interface ItemManager extends Manageable, ModelGenerator { boolean addCustomItem(CustomItem customItem); - List tagToItems(Key tag); + default List itemIdsByTag(Key tag) { + List items = new ArrayList<>(); + items.addAll(vanillaItemIdsByTag(tag)); + items.addAll(customItemIdsByTag(tag)); + return items; + } - List tagToVanillaItems(Key tag); + List vanillaItemIdsByTag(Key tag); - List tagToCustomItems(Key tag); + List customItemIdsByTag(Key tag); int fuelTime(T itemStack); @@ -108,4 +110,6 @@ public interface ItemManager extends Manageable, ModelGenerator { UniqueIdItem uniqueEmptyItem(); Item applyTrim(Item base, Item addition, Item template, Key pattern); + + Item build(DatapackRecipeResult result); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java index 9b71c93ce..9af70aabb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java @@ -10,7 +10,7 @@ public abstract class AbstractGroupedRecipe implements FixedResultRecipe { protected final CustomRecipeResult result; protected AbstractGroupedRecipe(Key id, String group, CustomRecipeResult result) { - this.group = group; + this.group = group == null ? "" : group; this.id = id; this.result = result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java deleted file mode 100644 index 42f10cfae..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe; - -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.*; - -import java.util.*; - -public abstract class AbstractRecipeFactory implements RecipeFactory { - - protected List ingredients(Map arguments) { - return MiscUtils.getAsStringList(getIngredientOrThrow(arguments)); - } - - protected Map ingredientMap(Map arguments) { - return MiscUtils.castToMap(getIngredientOrThrow(arguments), true); - } - - protected Set ingredientHolders(Map arguments) { - Set holders = new HashSet<>(); - for (String item : ingredients(arguments)) { - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(UniqueKey.create(Key.of(item))); - } - } - return holders; - } - - protected Object getIngredientOrThrow(Map arguments) { - Object ingredient = ResourceConfigUtils.get(arguments, "ingredient", "ingredients"); - if (ingredient == null) { - throw new LocalizedResourceConfigException("warning.config.recipe.missing_ingredient"); - } - return ingredient; - } - - protected CookingRecipeCategory cookingRecipeCategory(Map arguments) { - CookingRecipeCategory recipeCategory; - try { - recipeCategory = arguments.containsKey("category") ? CookingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.recipe.cooking.invalid_category", e, arguments.get("category").toString(), EnumUtils.toString(CookingRecipeCategory.values())); - } - return recipeCategory; - } - - protected CraftingRecipeCategory craftingRecipeCategory(Map arguments) { - CraftingRecipeCategory recipeCategory; - try { - recipeCategory = arguments.containsKey("category") ? CraftingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.recipe.crafting.invalid_category", e, arguments.get("category").toString(), EnumUtils.toString(CraftingRecipeCategory.values())); - } - return recipeCategory; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java index 5334d96ae..796c79e9f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -1,11 +1,6 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; -import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20_5; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_2; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_5; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -14,24 +9,20 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; -import net.momirealms.craftengine.core.util.VersionHelper; import org.jetbrains.annotations.Nullable; import java.nio.file.Path; import java.util.*; public abstract class AbstractRecipeManager implements RecipeManager { - protected final VanillaRecipeReader recipeReader; protected final Map>> byType = new HashMap<>(); protected final Map> byId = new HashMap<>(); protected final Map>> byResult = new HashMap<>(); protected final Map>> byIngredient = new HashMap<>(); protected final Set dataPackRecipes = new HashSet<>(); protected final RecipeParser recipeParser; - protected boolean isReloading; public AbstractRecipeManager() { - this.recipeReader = initVanillaRecipeReader(); this.recipeParser = new RecipeParser(); } @@ -40,18 +31,6 @@ public abstract class AbstractRecipeManager implements RecipeManager { return this.recipeParser; } - private VanillaRecipeReader initVanillaRecipeReader() { - if (VersionHelper.isOrAbove1_21_5()) { - return new VanillaRecipeReader1_21_5(); - } else if (VersionHelper.isOrAbove1_21_2()) { - return new VanillaRecipeReader1_21_2(); - } else if (VersionHelper.isOrAbove1_20_5()) { - return new VanillaRecipeReader1_20_5(); - } else { - return new VanillaRecipeReader1_20(); - } - } - @Override public void unload() { this.dataPackRecipes.clear(); @@ -67,44 +46,37 @@ public abstract class AbstractRecipeManager implements RecipeManager { @Override public boolean isDataPackRecipe(Key key) { - if (this.isReloading) return false; return this.dataPackRecipes.contains(key); } @Override public boolean isCustomRecipe(Key key) { - if (this.isReloading) return false; return this.byId.containsKey(key); } @Override public Optional> recipeById(Key key) { - if (this.isReloading) return Optional.empty(); return Optional.ofNullable(this.byId.get(key)); } @Override public List> recipesByType(RecipeType type) { - if (this.isReloading) return List.of(); return this.byType.getOrDefault(type, List.of()); } @Override public List> recipeByResult(Key result) { - if (this.isReloading) return List.of(); return this.byResult.getOrDefault(result, List.of()); } @Override public List> recipeByIngredient(Key ingredient) { - if (this.isReloading) return List.of(); return this.byIngredient.getOrDefault(ingredient, List.of()); } @Nullable @Override public Recipe recipeByInput(RecipeType type, RecipeInput input) { - if (this.isReloading) return null; List> recipes = this.byType.get(type); if (recipes == null) return null; for (Recipe recipe : recipes) { @@ -118,7 +90,6 @@ public abstract class AbstractRecipeManager implements RecipeManager { @Nullable @Override public Recipe recipeByInput(RecipeType type, RecipeInput input, Key lastRecipe) { - if (this.isReloading) return null; if (lastRecipe != null) { Recipe last = this.byId.get(lastRecipe); if (last != null && last.matches(input)) { @@ -128,7 +99,8 @@ public abstract class AbstractRecipeManager implements RecipeManager { return recipeByInput(type, input); } - protected void registerInternalRecipe(Key id, Recipe recipe) { + protected boolean registerInternalRecipe(Key id, Recipe recipe) { + if (this.byId.containsKey(id)) return false; this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe); this.byId.put(id, recipe); if (recipe instanceof FixedResultRecipe fixedResult) { @@ -143,6 +115,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { } } } + return true; } public class RecipeParser implements ConfigParser { @@ -167,7 +140,6 @@ public abstract class AbstractRecipeManager implements RecipeManager { Recipe recipe = RecipeSerializers.fromMap(id, section); try { registerInternalRecipe(id, recipe); - registerPlatformRecipe(id, recipe); } catch (LocalizedResourceConfigException e) { throw e; } catch (Exception e) { @@ -176,7 +148,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { } } - protected abstract void unregisterPlatformRecipe(Key key, boolean isBrewingRecipe); + protected abstract void unregisterPlatformRecipeMainThread(Key key, boolean isBrewingRecipe); - protected abstract void registerPlatformRecipe(Key key, Recipe recipe); + protected abstract void registerPlatformRecipeMainThread(Recipe recipe); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java new file mode 100644 index 000000000..4c17b43a1 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -0,0 +1,119 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.CloneableConstantItem; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemManager; +import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20; +import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20_5; +import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_21_2; +import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.*; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public abstract class AbstractRecipeSerializer> implements RecipeSerializer { + protected static final VanillaRecipeReader VANILLA_RECIPE_HELPER = + VersionHelper.isOrAbove1_21_2() ? + new VanillaRecipeReader1_21_2() : + VersionHelper.isOrAbove1_20_5() ? + new VanillaRecipeReader1_20_5() : + new VanillaRecipeReader1_20(); + + protected Ingredient singleInputIngredient(Map arguments) { + List ingredients = MiscUtils.getAsStringList(getIngredientOrThrow(arguments)); + return toIngredient(ingredients); + } + + // 不确定的类型 + protected Object getIngredientOrThrow(Map arguments) { + Object ingredient = ResourceConfigUtils.get(arguments, "ingredient", "ingredients"); + if (ingredient == null) { + throw new LocalizedResourceConfigException("warning.config.recipe.missing_ingredient"); + } + return ingredient; + } + + protected CookingRecipeCategory cookingRecipeCategory(Map arguments) { + CookingRecipeCategory recipeCategory; + try { + recipeCategory = arguments.containsKey("category") ? CookingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.recipe.cooking.invalid_category", e, arguments.get("category").toString(), EnumUtils.toString(CookingRecipeCategory.values())); + } + return recipeCategory; + } + + protected CraftingRecipeCategory craftingRecipeCategory(Map arguments) { + CraftingRecipeCategory recipeCategory; + try { + recipeCategory = arguments.containsKey("category") ? CraftingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.recipe.crafting.invalid_category", e, arguments.get("category").toString(), EnumUtils.toString(CraftingRecipeCategory.values())); + } + return recipeCategory; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + protected CustomRecipeResult parseResult(Map arguments) { + Map resultMap = MiscUtils.castToMap(arguments.get("result"), true); + if (resultMap == null) { + throw new LocalizedResourceConfigException("warning.config.recipe.missing_result"); + } + String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(resultMap.get("id"), "warning.config.recipe.result.missing_id"); + int count = ResourceConfigUtils.getAsInt(resultMap.getOrDefault("count", 1), "count"); + List> processors = ResourceConfigUtils.parseConfigAsList(resultMap.get("post-processors"), CustomRecipeResult.PostProcessor::fromMap); + return new CustomRecipeResult( + CraftEngine.instance().itemManager().getBuildableItem(Key.of(id)).orElseThrow(() -> new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id)), + count, + processors.isEmpty() ? null : processors.toArray(new CustomRecipeResult.PostProcessor[0]) + ); + } + + @SuppressWarnings("unchecked") + protected CustomRecipeResult parseResult(DatapackRecipeResult recipeResult) { + Item result = (Item) CraftEngine.instance().itemManager().build(recipeResult); + return new CustomRecipeResult<>(CloneableConstantItem.of(result), recipeResult.count(), null); + } + + @Nullable + protected Ingredient toIngredient(String item) { + return toIngredient(List.of(item)); + } + + @Nullable + protected Ingredient toIngredient(List items) { + Set itemIds = new HashSet<>(); + Set minecraftItemIds = new HashSet<>(); + ItemManager itemManager = CraftEngine.instance().itemManager(); + for (String item : items) { + if (item.charAt(0) == '#') itemIds.addAll(itemManager.itemIdsByTag(Key.of(item.substring(1)))); + else { + Key itemId = Key.of(item); + if (itemManager.getBuildableItem(itemId).isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", item); + } + itemIds.add(UniqueKey.create(itemId)); + } + } + boolean hasCustomItem = false; + for (UniqueKey holder : itemIds) { + Optional> optionalCustomItem = itemManager.getCustomItem(holder.key()); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + if (customItem.isVanillaItem()) { + minecraftItemIds.add(holder); + } else { + minecraftItemIds.add(UniqueKey.create(customItem.material())); + hasCustomItem = true; + } + } else { + minecraftItemIds.add(holder); + } + } + return itemIds.isEmpty() ? null : Ingredient.of(itemIds, minecraftItemIds, hasCustomItem); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java index 2ab483f74..3dcf683e7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java @@ -1,15 +1,14 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; -import java.util.Set; public class CustomBlastingRecipe extends CustomCookingRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); public CustomBlastingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); @@ -25,16 +24,31 @@ public class CustomBlastingRecipe extends CustomCookingRecipe { return RecipeType.BLASTING; } - public static class Factory extends AbstractRecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe create(Key id, Map arguments) { - String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; - int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); - float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set holders = ingredientHolders(arguments); - return new CustomBlastingRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); + public CustomBlastingRecipe readMap(Key id, Map arguments) { + return new CustomBlastingRecipe(id, + cookingRecipeCategory(arguments), + arguments.containsKey("group") ? arguments.get("group").toString() : null, + singleInputIngredient(arguments), + ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"), + parseResult(arguments) + ); + } + + @Override + public CustomBlastingRecipe readJson(Key id, JsonObject json) { + return new CustomBlastingRecipe<>(id, + VANILLA_RECIPE_HELPER.cookingCategory(json), + VANILLA_RECIPE_HELPER.readGroup(json), + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("ingredient"))), + VANILLA_RECIPE_HELPER.cookingTime(json), + VANILLA_RECIPE_HELPER.cookingExperience(json), + parseResult(VANILLA_RECIPE_HELPER.cookingResult(json.get("result"))) + ); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java index 012eefc78..994af19c4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.input.BrewingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; @@ -14,7 +15,7 @@ import java.util.List; import java.util.Map; public class CustomBrewingRecipe implements FixedResultRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); private final Key id; private final Ingredient container; private final Ingredient ingredient; @@ -81,10 +82,10 @@ public class CustomBrewingRecipe implements FixedResultRecipe { } @SuppressWarnings({"DuplicatedCode"}) - public static class Factory implements RecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @Override - public Recipe create(Key id, Map arguments) { + public CustomBrewingRecipe readMap(Key id, Map arguments) { List container = MiscUtils.getAsStringList(arguments.get("container")); if (container.isEmpty()) { throw new LocalizedResourceConfigException("warning.config.recipe.brewing.missing_container"); @@ -98,5 +99,10 @@ public class CustomBrewingRecipe implements FixedResultRecipe { ResourceConfigUtils.requireNonNullOrThrow(toIngredient(ingredient), "warning.config.recipe.brewing.missing_ingredient"), parseResult(arguments)); } + + @Override + public CustomBrewingRecipe readJson(Key id, JsonObject json) { + throw new UnsupportedOperationException(); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java index 6f34328fa..de0afd5a6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java @@ -1,15 +1,14 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; -import java.util.Set; public class CustomCampfireRecipe extends CustomCookingRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); public CustomCampfireRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); @@ -25,16 +24,31 @@ public class CustomCampfireRecipe extends CustomCookingRecipe { return RecipeType.CAMPFIRE_COOKING; } - public static class Factory extends AbstractRecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe create(Key id, Map arguments) { - String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; - int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); - float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set holders = ingredientHolders(arguments); - return new CustomCampfireRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); + public CustomCampfireRecipe readMap(Key id, Map arguments) { + return new CustomCampfireRecipe(id, + cookingRecipeCategory(arguments), + arguments.containsKey("group") ? arguments.get("group").toString() : null, + singleInputIngredient(arguments), + ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"), + parseResult(arguments) + ); + } + + @Override + public CustomCampfireRecipe readJson(Key id, JsonObject json) { + return new CustomCampfireRecipe<>(id, + VANILLA_RECIPE_HELPER.cookingCategory(json), + VANILLA_RECIPE_HELPER.readGroup(json), + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("ingredient"))), + VANILLA_RECIPE_HELPER.cookingTime(json), + VANILLA_RECIPE_HELPER.cookingExperience(json), + parseResult(VANILLA_RECIPE_HELPER.cookingResult(json.get("result"))) + ); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java index 423470eb1..87847a545 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java @@ -20,7 +20,7 @@ public abstract class CustomCookingRecipe extends AbstractGroupedRecipe { float experience, CustomRecipeResult result) { super(id, group, result); - this.category = category; + this.category = category == null ? CookingRecipeCategory.MISC : category; this.ingredient = ingredient; this.experience = experience; this.cookingTime = cookingTime; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java index 5d2c241fe..9eb9153d4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java @@ -7,7 +7,7 @@ public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe protected CustomCraftingTableRecipe(Key id, CraftingRecipeCategory category, String group, CustomRecipeResult result) { super(id, group, result); - this.category = category; + this.category = category == null ? CraftingRecipeCategory.MISC : category; } public CraftingRecipeCategory category() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java index 0afc9ab64..aff047c53 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java @@ -4,10 +4,12 @@ import net.momirealms.craftengine.core.item.BuildableItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; import java.util.ArrayList; @@ -19,19 +21,24 @@ import java.util.Optional; public record CustomRecipeResult(BuildableItem item, int count, PostProcessor[] postProcessors) { public T buildItemStack(ItemBuildContext context) { + return buildItem(context).getItem(); + } + + public Item buildItem(ItemBuildContext context) { Item builtItem = this.item.buildItem(context, count); if (this.postProcessors != null) { for (PostProcessor postProcessor : this.postProcessors) { builtItem = postProcessor.process(builtItem, context); } } - return builtItem.getItem(); + return builtItem; } static { registerPostProcessorType(Key.of("apply_data"), args -> { List> modifiers = new ArrayList<>(); - for (Map.Entry entry : args.entrySet()) { + Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); + for (Map.Entry entry : data.entrySet()) { Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), "craftengine"))) .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); } @@ -40,12 +47,23 @@ public record CustomRecipeResult(BuildableItem item, int count, PostProces } public static void registerPostProcessorType(Key id, PostProcessor.Type type) { - ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE).register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); + ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE) + .register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); } @FunctionalInterface public interface PostProcessor { + static PostProcessor fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.recipe.result.post_processor.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + PostProcessor.Type processor = (PostProcessor.Type) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE.getValue(key); + if (processor == null) { + throw new LocalizedResourceConfigException("warning.config.recipe.result.post_processor.invalid_type", type); + } + return processor.create(map); + } + Item process(Item item, ItemBuildContext context); interface Type { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java index 274a2e5a8..4e7d62a5d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java @@ -1,18 +1,19 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.common.collect.Maps; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.UniqueKey; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.NotNull; import java.util.*; public class CustomShapedRecipe extends CustomCraftingTableRecipe { - public static final Factory FACTORY = new Factory>(); + public static final Serializer SERIALIZER = new Serializer>(); private final ParsedPattern parsedPattern; private final Pattern pattern; @@ -133,11 +134,11 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { } } - public static class Factory extends AbstractRecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe create(Key id, Map arguments) { + public CustomShapedRecipe readMap(Key id, Map arguments) { List pattern = MiscUtils.getAsStringList(arguments.get("pattern")); if (pattern.isEmpty()) { throw new LocalizedResourceConfigException("warning.config.recipe.shaped.missing_pattern"); @@ -146,30 +147,37 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { throw new LocalizedResourceConfigException("warning.config.recipe.shaped.invalid_pattern", pattern.toString()); } Object ingredientObj = getIngredientOrThrow(arguments); - String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; Map> ingredients = new HashMap<>(); - for (Map.Entry entry : MiscUtils.castToMap(ingredientObj, false).entrySet()) { + for (Map.Entry entry : ResourceConfigUtils.getAsMap(ingredientObj, "ingredient").entrySet()) { String key = entry.getKey(); if (key.length() != 1) { throw new LocalizedResourceConfigException("warning.config.recipe.shaped.invalid_symbol", key); } char ch = key.charAt(0); List items = MiscUtils.getAsStringList(entry.getValue()); - Set holders = new HashSet<>(); - for (String item : items) { - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(UniqueKey.create(Key.of(item))); - } - } - ingredients.put(ch, Ingredient.of(holders)); + ingredients.put(ch, toIngredient(items)); } - return new CustomShapedRecipe(id, craftingRecipeCategory(arguments), group, new Pattern<>(pattern.toArray(new String[0]), ingredients), parseResult(arguments)); + return new CustomShapedRecipe(id, + craftingRecipeCategory(arguments), + arguments.containsKey("group") ? arguments.get("group").toString() : null, + new Pattern<>(pattern.toArray(new String[0]), ingredients), + parseResult(arguments) + ); + } + + @Override + public CustomShapedRecipe readJson(Key id, JsonObject json) { + Map> ingredients = Maps.transformValues(VANILLA_RECIPE_HELPER.shapedIngredientMap(json.getAsJsonObject("key")), this::toIngredient); + return new CustomShapedRecipe<>(id, + VANILLA_RECIPE_HELPER.craftingCategory(json), + VANILLA_RECIPE_HELPER.readGroup(json), + new Pattern<>(VANILLA_RECIPE_HELPER.craftingShapedPattern(json), ingredients), + parseResult(VANILLA_RECIPE_HELPER.craftingResult(json.getAsJsonObject("result"))) + ); } private boolean validatePattern(List pattern) { - String first = pattern.get(0); + String first = pattern.getFirst(); int length = first.length(); for (String s : pattern) { if (s.length() != length) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java index aae980768..9449ec83f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java @@ -1,17 +1,18 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; public class CustomShapelessRecipe extends CustomCraftingTableRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); private final List> ingredients; private final PlacementInfo placementInfo; @@ -51,61 +52,45 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { return RecipeSerializers.SHAPELESS; } - public static class Factory extends AbstractRecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe create(Key id, Map arguments) { - String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; + public CustomShapelessRecipe readMap(Key id, Map arguments) { List> ingredients = new ArrayList<>(); Object ingredientsObject = getIngredientOrThrow(arguments); if (ingredientsObject instanceof Map map) { for (Map.Entry entry : (MiscUtils.castToMap(map, false)).entrySet()) { - List items = MiscUtils.getAsStringList(entry.getValue()); - Set holders = new HashSet<>(); - for (String item : items) { - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(UniqueKey.create(Key.of(item))); - } - } - ingredients.add(Ingredient.of(holders)); + if (entry.getValue() == null) continue; + ingredients.add(toIngredient(MiscUtils.getAsStringList(entry.getValue()))); } } else if (ingredientsObject instanceof List list) { for (Object obj : list) { if (obj instanceof List inner) { - Set holders = new HashSet<>(); - for (String item : MiscUtils.getAsStringList(inner)) { - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(UniqueKey.create(Key.of(item))); - } - } - ingredients.add(Ingredient.of(holders)); + ingredients.add(toIngredient(MiscUtils.getAsStringList(inner))); } else { String item = obj.toString(); - Set holders = new HashSet<>(); - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(UniqueKey.create(Key.of(item))); - } - ingredients.add(Ingredient.of(holders)); + ingredients.add(toIngredient(item)); } } } else { - String item = ingredientsObject.toString(); - Set holders = new HashSet<>(); - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(UniqueKey.create(Key.of(item))); - } - ingredients.add(Ingredient.of(holders)); + ingredients.add(toIngredient(ingredientsObject.toString())); } - return new CustomShapelessRecipe(id, craftingRecipeCategory(arguments), group, ingredients, parseResult(arguments)); + return new CustomShapelessRecipe(id, + craftingRecipeCategory(arguments), + arguments.containsKey("group") ? arguments.get("group").toString() : null, + ingredients, + parseResult(arguments)); + } + + @Override + public CustomShapelessRecipe readJson(Key id, JsonObject json) { + return new CustomShapelessRecipe<>(id, + VANILLA_RECIPE_HELPER.craftingCategory(json), + VANILLA_RECIPE_HELPER.readGroup(json), + VANILLA_RECIPE_HELPER.shapelessIngredients(json.getAsJsonArray("ingredients")).stream().map(this::toIngredient).toList(), + parseResult(VANILLA_RECIPE_HELPER.craftingResult(json.getAsJsonObject("result"))) + ); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java index ef0dc9a6c..2b03dec6e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java @@ -1,15 +1,14 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; -import java.util.Set; public class CustomSmeltingRecipe extends CustomCookingRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); public CustomSmeltingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); @@ -25,16 +24,31 @@ public class CustomSmeltingRecipe extends CustomCookingRecipe { return RecipeType.SMELTING; } - public static class Factory extends AbstractRecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe create(Key id, Map arguments) { - String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; - int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); - float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set holders = ingredientHolders(arguments); - return new CustomSmeltingRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); + public CustomSmeltingRecipe readMap(Key id, Map arguments) { + return new CustomSmeltingRecipe(id, + cookingRecipeCategory(arguments), + arguments.containsKey("group") ? arguments.get("group").toString() : null, + singleInputIngredient(arguments), + ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"), + parseResult(arguments) + ); + } + + @Override + public CustomSmeltingRecipe readJson(Key id, JsonObject json) { + return new CustomSmeltingRecipe<>(id, + VANILLA_RECIPE_HELPER.cookingCategory(json), + VANILLA_RECIPE_HELPER.readGroup(json), + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("ingredient"))), + VANILLA_RECIPE_HELPER.cookingTime(json), + VANILLA_RECIPE_HELPER.cookingExperience(json), + parseResult(VANILLA_RECIPE_HELPER.cookingResult(json.get("result"))) + ); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index 80bafeccf..f1134f90f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; @@ -16,9 +17,10 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; public class CustomSmithingTransformRecipe implements FixedResultRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); private final Key id; private final CustomRecipeResult result; private final Ingredient base; @@ -28,7 +30,7 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { private final List processors; public CustomSmithingTransformRecipe(Key id, - @Nullable Ingredient base, + @NotNull Ingredient base, @Nullable Ingredient template, @Nullable Ingredient addition, CustomRecipeResult result, @@ -118,7 +120,7 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { return this.result; } - @Nullable + @NotNull public Ingredient base() { return this.base; } @@ -134,26 +136,37 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { } @SuppressWarnings({"DuplicatedCode"}) - public static class Factory implements RecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @Override - public Recipe create(Key id, Map arguments) { + public CustomSmithingTransformRecipe readMap(Key id, Map arguments) { List base = MiscUtils.getAsStringList(arguments.get("base")); - if (base.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.recipe.smithing_transform.missing_base"); - } - List addition = MiscUtils.getAsStringList(arguments.get("addition")); List template = MiscUtils.getAsStringList(arguments.get("template-type")); + List addition = MiscUtils.getAsStringList(arguments.get("addition")); boolean mergeComponents = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-components", true), "merge-components"); @SuppressWarnings("unchecked") List> processors = (List>) arguments.getOrDefault("post-processors", List.of()); - return new CustomSmithingTransformRecipe<>( - id, - toIngredient(base), toIngredient(template),toIngredient(addition), parseResult(arguments), + return new CustomSmithingTransformRecipe<>(id, + ResourceConfigUtils.requireNonNullOrThrow(toIngredient(base), "warning.config.recipe.smithing_transform.missing_base"), + toIngredient(template), + toIngredient(addition), + parseResult(arguments), mergeComponents, ItemDataProcessors.fromMapList(processors) ); } + + @Override + public CustomSmithingTransformRecipe readJson(Key id, JsonObject json) { + return new CustomSmithingTransformRecipe<>(id, + Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))), + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template"))), + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition"))), + parseResult(VANILLA_RECIPE_HELPER.smithingResult(json.getAsJsonObject("result"))), + true, + null + ); + } } public static class ItemDataProcessors { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java index 18d1b7062..51c2a5491 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java @@ -1,11 +1,11 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -16,9 +16,10 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; public class CustomSmithingTrimRecipe implements Recipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); private final Key id; private final Ingredient base; private final Ingredient template; @@ -60,14 +61,7 @@ public class CustomSmithingTrimRecipe implements Recipe { } private boolean checkIngredient(Ingredient ingredient, UniqueIdItem item) { - if (ingredient != null) { - if (item == null || item.isEmpty()) { - return false; - } - return ingredient.test(item); - } else { - return item == null || item.isEmpty(); - } + return ingredient.test(item); } @Override @@ -94,17 +88,17 @@ public class CustomSmithingTrimRecipe implements Recipe { return this.id; } - @Nullable + @NotNull public Ingredient base() { return this.base; } - @Nullable + @NotNull public Ingredient template() { return template; } - @Nullable + @NotNull public Ingredient addition() { return addition; } @@ -115,22 +109,13 @@ public class CustomSmithingTrimRecipe implements Recipe { } @SuppressWarnings({"DuplicatedCode"}) - public static class Factory implements RecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @Override - public Recipe create(Key id, Map arguments) { + public CustomSmithingTrimRecipe readMap(Key id, Map arguments) { List base = MiscUtils.getAsStringList(arguments.get("base")); - if (base.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_base"); - } - List addition = MiscUtils.getAsStringList(arguments.get("addition")); - if (addition.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_addition"); - } List template = MiscUtils.getAsStringList(arguments.get("template-type")); - if (template.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_template_type"); - } + List addition = MiscUtils.getAsStringList(arguments.get("addition")); Key pattern = VersionHelper.isOrAbove1_21_5() ? Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("pattern"), "warning.config.recipe.smithing_trim.missing_pattern")) : null; return new CustomSmithingTrimRecipe<>(id, ResourceConfigUtils.requireNonNullOrThrow(toIngredient(base), "warning.config.recipe.smithing_trim.missing_base"), @@ -138,5 +123,15 @@ public class CustomSmithingTrimRecipe implements Recipe { ResourceConfigUtils.requireNonNullOrThrow(toIngredient(addition), "warning.config.recipe.smithing_trim.missing_addition"), pattern); } + + @Override + public CustomSmithingTrimRecipe readJson(Key id, JsonObject json) { + return new CustomSmithingTrimRecipe<>(id, + Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))), + Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template")))), + Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition")))), + VersionHelper.isOrAbove1_21_5() ? Key.of(json.get("pattern").getAsString()) : null + ); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java index 1ea3590af..e59d341de 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java @@ -1,15 +1,14 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; -import java.util.Set; public class CustomSmokingRecipe extends CustomCookingRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); public CustomSmokingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); @@ -25,16 +24,31 @@ public class CustomSmokingRecipe extends CustomCookingRecipe { return RecipeType.SMOKING; } - public static class Factory extends AbstractRecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe create(Key id, Map arguments) { - String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; - int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); - float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set holders = ingredientHolders(arguments); - return new CustomSmokingRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); + public CustomSmokingRecipe readMap(Key id, Map arguments) { + return new CustomSmokingRecipe(id, + cookingRecipeCategory(arguments), + arguments.containsKey("group") ? arguments.get("group").toString() : null, + singleInputIngredient(arguments), + ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"), + parseResult(arguments) + ); + } + + @Override + public CustomSmokingRecipe readJson(Key id, JsonObject json) { + return new CustomSmokingRecipe<>(id, + VANILLA_RECIPE_HELPER.cookingCategory(json), + VANILLA_RECIPE_HELPER.readGroup(json), + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("ingredient"))), + VANILLA_RECIPE_HELPER.cookingTime(json), + VANILLA_RECIPE_HELPER.cookingExperience(json), + parseResult(VANILLA_RECIPE_HELPER.cookingResult(json.get("result"))) + ); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java index 485dc6b74..3bc3a14e9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java @@ -1,17 +1,16 @@ package net.momirealms.craftengine.core.item.recipe; +import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Map; -import java.util.Set; public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { - public static final Factory FACTORY = new Factory<>(); + public static final Serializer SERIALIZER = new Serializer<>(); protected final Ingredient ingredient; public CustomStoneCuttingRecipe(Key id, String group, Ingredient ingredient, CustomRecipeResult result) { @@ -27,7 +26,7 @@ public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { @Override public List> ingredientsInUse() { - return List.of(ingredient); + return List.of(this.ingredient); } @Override @@ -41,17 +40,22 @@ public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { } public Ingredient ingredient() { - return ingredient; + return this.ingredient; } - public static class Factory extends AbstractRecipeFactory { + public static class Serializer extends AbstractRecipeSerializer> { @SuppressWarnings({"DuplicatedCode"}) @Override - public Recipe create(Key id, Map arguments) { + public CustomStoneCuttingRecipe readMap(Key id, Map arguments) { String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; - Set holders = ingredientHolders(arguments); - return new CustomStoneCuttingRecipe<>(id, group, Ingredient.of(holders), parseResult(arguments)); + return new CustomStoneCuttingRecipe<>(id, group, singleInputIngredient(arguments), parseResult(arguments)); + } + + @Override + public CustomStoneCuttingRecipe readJson(Key id, JsonObject json) { + String group = VANILLA_RECIPE_HELPER.readGroup(json); + return new CustomStoneCuttingRecipe<>(id, group, toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("ingredient"))), parseResult(VANILLA_RECIPE_HELPER.stoneCuttingResult(json))); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/DatapackRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/DatapackRecipeResult.java new file mode 100644 index 000000000..4f2f388e4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/DatapackRecipeResult.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.item.recipe; + +import com.google.gson.JsonObject; + +public record DatapackRecipeResult(String id, int count, JsonObject components) { + + public boolean isCustom() { + return components != null; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java index db368e605..6d2f1ce02 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java @@ -6,10 +6,17 @@ import java.util.*; import java.util.function.Predicate; public class Ingredient implements Predicate>, StackedContents.IngredientInfo { + // 自定义物品与原版物品混合的列表 private final List items; + // 自定义物品原版材质与原版物品混合的列表 + private final List vanillaItems; + // ingredient里是否含有自定义物品 + private final boolean hasCustomItem; - public Ingredient(List items) { - this.items = items; + private Ingredient(List items, List vanillaItems, boolean hasCustomItem) { + this.items = List.copyOf(items); + this.vanillaItems = List.copyOf(vanillaItems); + this.hasCustomItem = hasCustomItem; } public static boolean isInstance(Optional> optionalIngredient, UniqueIdItem stack) { @@ -17,12 +24,12 @@ public class Ingredient implements Predicate>, StackedContent .orElseGet(stack::isEmpty); } - public static Ingredient of(List items) { - return new Ingredient<>(items); + public static Ingredient of(Set items, Set minecraftItems, boolean hasCustomItem) { + return new Ingredient<>(new ArrayList<>(items), new ArrayList<>(minecraftItems), hasCustomItem); } - public static Ingredient of(Set items) { - return new Ingredient<>(new ArrayList<>(items)); + public boolean hasCustomItem() { + return hasCustomItem; } @Override @@ -39,6 +46,10 @@ public class Ingredient implements Predicate>, StackedContent return this.items; } + public List minecraftItems() { + return vanillaItems; + } + @Override public String toString() { StringJoiner joiner = new StringJoiner(", "); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java index 2068a735b..db3d2f675 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java @@ -21,4 +21,8 @@ public interface Recipe { RecipeType type(); Key id(); + + default boolean showNotification() { + return true; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java deleted file mode 100644 index 563b8ca1c..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe; - -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -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.util.UniqueKey; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public interface RecipeFactory { - - Recipe create(Key id, Map arguments); - - @SuppressWarnings({"unchecked", "rawtypes"}) - default CustomRecipeResult parseResult(Map arguments) { - Map resultMap = MiscUtils.castToMap(arguments.get("result"), true); - if (resultMap == null) { - throw new LocalizedResourceConfigException("warning.config.recipe.missing_result"); - } - String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(resultMap.get("id"), "warning.config.recipe.result.missing_id"); - int count = ResourceConfigUtils.getAsInt(resultMap.getOrDefault("count", 1), "count"); - return new CustomRecipeResult( - CraftEngine.instance().itemManager().getBuildableItem(Key.of(id)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id)), - count, - null - ); - } - - default Ingredient toIngredient(List items) { - Set holders = new HashSet<>(); - for (String item : items) { - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(UniqueKey.create(Key.of(item))); - } - } - return holders.isEmpty() ? null : Ingredient.of(holders); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializer.java new file mode 100644 index 000000000..f307bbb45 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializer.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.item.recipe; + +import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Map; + +public interface RecipeSerializer> { + + R readMap(Key id, Map arguments); + + R readJson(Key id, JsonObject json); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializers.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializers.java index 4ba3385db..0d3fe7b12 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeSerializers.java @@ -23,31 +23,34 @@ public final class RecipeSerializers { public static final Key BREWING = Key.of("minecraft:brewing"); static { - register(SHAPED, CustomShapedRecipe.FACTORY); - register(SHAPELESS, CustomShapelessRecipe.FACTORY); - register(SMELTING, CustomSmeltingRecipe.FACTORY); - register(SMOKING, CustomSmokingRecipe.FACTORY); - register(BLASTING, CustomBlastingRecipe.FACTORY); - register(CAMPFIRE_COOKING, CustomCampfireRecipe.FACTORY); - register(STONECUTTING, CustomStoneCuttingRecipe.FACTORY); - register(SMITHING_TRANSFORM, CustomSmithingTransformRecipe.FACTORY); - register(SMITHING_TRIM, CustomSmithingTrimRecipe.FACTORY); - register(BREWING, CustomBrewingRecipe.FACTORY); + register(SHAPED, CustomShapedRecipe.SERIALIZER); + register(Key.of("crafting_shaped"), CustomShapedRecipe.SERIALIZER); + register(SHAPELESS, CustomShapelessRecipe.SERIALIZER); + register(Key.of("crafting_shapeless"), CustomShapelessRecipe.SERIALIZER); + register(SMELTING, CustomSmeltingRecipe.SERIALIZER); + register(SMOKING, CustomSmokingRecipe.SERIALIZER); + register(BLASTING, CustomBlastingRecipe.SERIALIZER); + register(CAMPFIRE_COOKING, CustomCampfireRecipe.SERIALIZER); + register(STONECUTTING, CustomStoneCuttingRecipe.SERIALIZER); + register(SMITHING_TRANSFORM, CustomSmithingTransformRecipe.SERIALIZER); + register(SMITHING_TRIM, CustomSmithingTrimRecipe.SERIALIZER); + register(BREWING, CustomBrewingRecipe.SERIALIZER); } - public static void register(Key key, RecipeFactory factory) { - ((WritableRegistry>) BuiltInRegistries.RECIPE_FACTORY) - .register(ResourceKey.create(Registries.RECIPE_FACTORY.location(), key), factory); + @SuppressWarnings({"unchecked", "rawtypes"}) + public static > void register(Key key, RecipeSerializer serializer) { + WritableRegistry> registry = (WritableRegistry) BuiltInRegistries.RECIPE_SERIALIZER; + registry.register(ResourceKey.create(Registries.RECIPE_FACTORY.location(), key), serializer); } @SuppressWarnings("unchecked") - public static Recipe fromMap(Key id, Map map) { + public static > Recipe fromMap(Key id, Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.recipe.missing_type"); Key key = Key.withDefaultNamespace(type, "minecraft"); - RecipeFactory factory = (RecipeFactory) BuiltInRegistries.RECIPE_FACTORY.getValue(key); + RecipeSerializer factory = (RecipeSerializer) BuiltInRegistries.RECIPE_SERIALIZER.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.recipe.invalid_type", type); } - return factory.create(id, map); + return factory.readMap(id, map); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/UniqueIdItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/UniqueIdItem.java index 3166c9d00..7e60308d1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/UniqueIdItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/UniqueIdItem.java @@ -8,9 +8,13 @@ public class UniqueIdItem { private final Item rawItem; private final UniqueKey uniqueId; - public UniqueIdItem(@NotNull UniqueKey uniqueId, @NotNull Item rawItem) { - this.uniqueId = uniqueId; + private UniqueIdItem(@NotNull Item rawItem) { this.rawItem = rawItem; + this.uniqueId = rawItem.recipeIngredientId(); + } + + public static UniqueIdItem of(Item rawItem) { + return new UniqueIdItem<>(rawItem); } @NotNull @@ -28,7 +32,7 @@ public class UniqueIdItem { } public boolean isEmpty() { - return this.uniqueId == UniqueKey.AIR; + return this.uniqueId == null; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java index ec1757f31..1ab863933 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.item.recipe.input; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public final class SmithingInput implements RecipeInput { private final UniqueIdItem base; @@ -10,8 +9,8 @@ public final class SmithingInput implements RecipeInput { private final UniqueIdItem addition; public SmithingInput(@NotNull UniqueIdItem base, - @Nullable UniqueIdItem template, - @Nullable UniqueIdItem addition) { + @NotNull UniqueIdItem template, + @NotNull UniqueIdItem addition) { this.base = base; this.template = template; this.addition = addition; @@ -22,12 +21,12 @@ public final class SmithingInput implements RecipeInput { return base; } - @Nullable + @NotNull public UniqueIdItem template() { return template; } - @Nullable + @NotNull public UniqueIdItem addition() { return addition; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java new file mode 100644 index 000000000..4cf75aa23 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java @@ -0,0 +1,148 @@ +package net.momirealms.craftengine.core.item.recipe.reader; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; +import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class VanillaRecipeReader1_20 implements VanillaRecipeReader { + + @Override + public @NotNull DatapackRecipeResult cookingResult(JsonElement object) { + return new DatapackRecipeResult(object.getAsString(), 1, null); + } + + @Override + public @NotNull DatapackRecipeResult craftingResult(JsonObject object) { + String item = object.get("item").getAsString(); + int count = object.has("count") ? object.get("count").getAsInt() : 1; + return new DatapackRecipeResult(item, count, null); + } + + @Override + public @NotNull DatapackRecipeResult smithingResult(JsonObject object) { + String item = object.get("item").getAsString(); + return new DatapackRecipeResult(item, 1, null); + } + + @Override + public List> shapelessIngredients(JsonArray json) { + List> ingredients = new ArrayList<>(); + for (JsonElement element : json) { + if (element.isJsonObject()) { + JsonObject jsonObject = element.getAsJsonObject(); + if (jsonObject.has("item")) { + ingredients.add(List.of(jsonObject.get("item").getAsString())); + } else if (jsonObject.has("tag")) { + ingredients.add(List.of("#" + jsonObject.get("tag").getAsString())); + } + } else if (element.isJsonArray()) { + List ingredient = ingredientList((JsonArray) element); + ingredients.add(ingredient); + } + } + return ingredients; + } + + @Override + public Map> shapedIngredientMap(JsonObject json) { + Map> ingredients = new HashMap<>(); + for (Map.Entry entry : json.entrySet()) { + char c = entry.getKey().charAt(0); + if (entry.getValue().isJsonObject()) { + JsonObject argument = entry.getValue().getAsJsonObject(); + if (argument.has("item")) { + ingredients.put(c, List.of(argument.get("item").getAsString())); + } else if (argument.has("tag")) { + ingredients.put(c, List.of("#" + argument.get("tag").getAsString())); + } + } else if (entry.getValue().isJsonArray()) { + List items = ingredientList((JsonArray) entry.getValue()); + ingredients.put(c, items); + } + } + return ingredients; + } + + @Override + public @NotNull List ingredientList(JsonArray array) { + List items = new ArrayList<>(); + for (JsonElement element : array) { + if (element.isJsonObject()) { + JsonObject argument = element.getAsJsonObject(); + if (argument.has("item")) { + items.add(argument.get("item").getAsString()); + } else if (argument.has("tag")) { + items.add("#" + argument.get("tag").getAsString()); + } + } + } + return items; + } + + @Override + public String[] craftingShapedPattern(JsonObject object) { + JsonArray pattern = object.getAsJsonArray("pattern"); + List patternList = new ArrayList<>(); + for (JsonElement element : pattern) { + patternList.add(element.getAsString()); + } + return patternList.toArray(new String[0]); + } + + @Override + public @Nullable String readGroup(JsonObject object) { + return object.has("group") ? object.get("group").getAsString() : null; + } + + @Override + public @NotNull CraftingRecipeCategory craftingCategory(JsonObject object) { + return object.has("category") ? CraftingRecipeCategory.valueOf(object.get("category").getAsString().toUpperCase(Locale.ENGLISH)) : CraftingRecipeCategory.MISC; + } + + @Override + public @NotNull CookingRecipeCategory cookingCategory(JsonObject object) { + return object.has("category") ? CookingRecipeCategory.valueOf(object.get("category").getAsString().toUpperCase(Locale.ENGLISH)) : CookingRecipeCategory.MISC; + } + + @Override + public float cookingExperience(JsonObject object) { + return object.has("experience") ? object.get("experience").getAsFloat() : 0; + } + + @Override + public int cookingTime(JsonObject object) { + return object.has("cookingtime") ? object.get("cookingtime").getAsInt() : 200; + } + + @Override + public @NotNull DatapackRecipeResult stoneCuttingResult(JsonObject json) { + int count = json.has("count") ? json.get("count").getAsInt() : 1; + String result = json.get("result").getAsString(); + return new DatapackRecipeResult(result, count, null); + } + + @Override + public List singleIngredient(JsonElement json) { + List ingredients = new ArrayList<>(); + if (json.isJsonObject()) { + JsonObject argument = json.getAsJsonObject(); + if (argument.has("item")) { + ingredients.add(argument.get("item").getAsString()); + } else if (argument.has("tag")) { + ingredients.add("#" + argument.get("tag").getAsString()); + } + } else if (json.isJsonArray()) { + List items = ingredientList((JsonArray) json); + ingredients.addAll(items); + } + return ingredients; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20_5.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20_5.java new file mode 100644 index 000000000..806766772 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20_5.java @@ -0,0 +1,34 @@ +package net.momirealms.craftengine.core.item.recipe.reader; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; +import org.jetbrains.annotations.NotNull; + +public class VanillaRecipeReader1_20_5 extends VanillaRecipeReader1_20 { + + @Override + public @NotNull DatapackRecipeResult craftingResult(JsonObject object) { + String item = object.get("id").getAsString(); + JsonObject components = object.has("components") ? object.getAsJsonObject("components") : null; + int count = object.has("count") ? object.get("count").getAsInt() : 1; + return new DatapackRecipeResult(item, count, components); + } + + @NotNull + @Override + public DatapackRecipeResult cookingResult(JsonElement object) { + return craftingResult(object.getAsJsonObject()); + } + + @NotNull + @Override + public DatapackRecipeResult stoneCuttingResult(JsonObject json) { + return craftingResult(json.getAsJsonObject("result")); + } + + @Override + public @NotNull DatapackRecipeResult smithingResult(JsonObject object) { + return craftingResult(object.getAsJsonObject()); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_2.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_21_2.java similarity index 86% rename from core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_2.java rename to core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_21_2.java index eafec4a5a..bacb8037d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_2.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_21_2.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla.reader; +package net.momirealms.craftengine.core.item.recipe.reader; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -12,7 +12,7 @@ import java.util.Map; public class VanillaRecipeReader1_21_2 extends VanillaRecipeReader1_20_5 { @Override - protected List readSingleIngredient(JsonElement json) { + public List singleIngredient(JsonElement json) { if (json.isJsonPrimitive()) { return List.of(json.getAsString()); } else { @@ -26,7 +26,7 @@ public class VanillaRecipeReader1_21_2 extends VanillaRecipeReader1_20_5 { } @Override - protected Map> readShapedIngredientMap(JsonObject json) { + public Map> shapedIngredientMap(JsonObject json) { Map> ingredients = new HashMap<>(); for (Map.Entry entry : json.entrySet()) { char c = entry.getKey().charAt(0); @@ -44,7 +44,7 @@ public class VanillaRecipeReader1_21_2 extends VanillaRecipeReader1_20_5 { } @Override - protected List> readShapelessIngredients(JsonArray json) { + public List> shapelessIngredients(JsonArray json) { List> ingredients = new ArrayList<>(); for (JsonElement element : json) { if (element.isJsonPrimitive()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/RecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/RecipeResult.java deleted file mode 100644 index a00730bb0..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/RecipeResult.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import com.google.gson.JsonObject; - -public record RecipeResult(String id, int count, JsonObject components) { - - public boolean isCustom() { - return components != null; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java index bacbaa854..9a81d0698 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; @@ -8,7 +9,7 @@ import java.util.List; public class VanillaBlastingRecipe extends VanillaCookingRecipe { - public VanillaBlastingRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { + public VanillaBlastingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java index 5a2b1624a..ae53346b0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; @@ -8,7 +9,7 @@ import java.util.List; public class VanillaCampfireRecipe extends VanillaCookingRecipe { - public VanillaCampfireRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { + public VanillaCampfireRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java index 93d91f943..a87f385f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import java.util.List; @@ -10,7 +11,7 @@ public abstract class VanillaCookingRecipe extends VanillaGroupedRecipe { protected final float experience; protected final int cookingTime; - protected VanillaCookingRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { + protected VanillaCookingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { super(group, result); this.ingredient = ingredient; this.experience = experience; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java index d8cd3bdb5..80b19b799 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; public abstract class VanillaCraftingRecipe extends VanillaGroupedRecipe { protected final CraftingRecipeCategory category; - protected VanillaCraftingRecipe(CraftingRecipeCategory category, String group, RecipeResult result) { + protected VanillaCraftingRecipe(CraftingRecipeCategory category, String group, DatapackRecipeResult result) { super(group, result); this.category = category; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java index 99d4e9aed..0e3c3c81b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java @@ -1,10 +1,12 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; + public abstract class VanillaGroupedRecipe implements VanillaRecipe { protected final String group; - protected final RecipeResult result; + protected final DatapackRecipeResult result; - protected VanillaGroupedRecipe(String group, RecipeResult result) { + protected VanillaGroupedRecipe(String group, DatapackRecipeResult result) { this.group = group; this.result = result; } @@ -13,7 +15,7 @@ public abstract class VanillaGroupedRecipe implements VanillaRecipe { return group; } - public RecipeResult result() { + public DatapackRecipeResult result() { return result; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java index 343d9b06a..4b09b88c0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java @@ -1,24 +1,47 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; public interface VanillaRecipeReader { - VanillaShapedRecipe readShaped(JsonObject json); + @NotNull DatapackRecipeResult cookingResult(JsonElement object); - VanillaShapelessRecipe readShapeless(JsonObject json); + @NotNull DatapackRecipeResult craftingResult(JsonObject object); - VanillaBlastingRecipe readBlasting(JsonObject json); + @NotNull DatapackRecipeResult smithingResult(JsonObject object); - VanillaSmeltingRecipe readSmelting(JsonObject json); + List> shapelessIngredients(JsonArray json); - VanillaSmokingRecipe readSmoking(JsonObject json); + Map> shapedIngredientMap(JsonObject json); - VanillaCampfireRecipe readCampfire(JsonObject json); + @NotNull List ingredientList(JsonArray array); - VanillaStoneCuttingRecipe readStoneCutting(JsonObject json); + String[] craftingShapedPattern(JsonObject object); - VanillaSmithingTransformRecipe readSmithingTransform(JsonObject json); + @Nullable + String readGroup(JsonObject object); - VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json); + @NotNull + CraftingRecipeCategory craftingCategory(JsonObject object); + + @NotNull + CookingRecipeCategory cookingCategory(JsonObject object); + + float cookingExperience(JsonObject object); + + int cookingTime(JsonObject object); + + @NotNull DatapackRecipeResult stoneCuttingResult(JsonObject json); + + List singleIngredient(JsonElement json); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java index bedb18ef2..7b40adea4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; @@ -15,7 +16,7 @@ public class VanillaShapedRecipe extends VanillaCraftingRecipe { String group, Map> key, String[] pattern, - RecipeResult result) { + DatapackRecipeResult result) { super(category, group, result); this.key = key; this.pattern = pattern; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java index 1c2c912c3..54e9a01ba 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; @@ -9,7 +10,7 @@ import java.util.List; public class VanillaShapelessRecipe extends VanillaCraftingRecipe { private final List> ingredients; - public VanillaShapelessRecipe(CraftingRecipeCategory category, String group, List> ingredients, RecipeResult result) { + public VanillaShapelessRecipe(CraftingRecipeCategory category, String group, List> ingredients, DatapackRecipeResult result) { super(category, group, result); this.ingredients = ingredients; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java index 34db78614..f5bca29dc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; @@ -8,7 +9,7 @@ import java.util.List; public class VanillaSmeltingRecipe extends VanillaCookingRecipe { - public VanillaSmeltingRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { + public VanillaSmeltingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java index 213d352e8..8452b3f22 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java @@ -1,17 +1,18 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; import java.util.List; public class VanillaSmithingTransformRecipe implements VanillaRecipe { - private final RecipeResult result; + private final DatapackRecipeResult result; private final List base; private final List template; private final List addition; - public VanillaSmithingTransformRecipe(List base, List template, List addition, RecipeResult result) { + public VanillaSmithingTransformRecipe(List base, List template, List addition, DatapackRecipeResult result) { this.result = result; this.base = base; this.template = template; @@ -23,7 +24,7 @@ public class VanillaSmithingTransformRecipe implements VanillaRecipe { return RecipeSerializers.SMITHING_TRANSFORM; } - public RecipeResult result() { + public DatapackRecipeResult result() { return result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java index fbb262398..cc22dea5c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; @@ -8,7 +9,7 @@ import java.util.List; public class VanillaSmokingRecipe extends VanillaCookingRecipe { - public VanillaSmokingRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { + public VanillaSmokingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java index 6770a90c9..a273f5e04 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; +import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; import net.momirealms.craftengine.core.util.Key; @@ -8,7 +9,7 @@ import java.util.List; public class VanillaStoneCuttingRecipe extends VanillaGroupedRecipe { private final List ingredient; - public VanillaStoneCuttingRecipe(String group, RecipeResult result, List ingredient) { + public VanillaStoneCuttingRecipe(String group, DatapackRecipeResult result, List ingredient) { super(group, result); this.ingredient = ingredient; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/AbstractRecipeReader.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/AbstractRecipeReader.java deleted file mode 100644 index 9422071a2..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/AbstractRecipeReader.java +++ /dev/null @@ -1,48 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla.reader; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public abstract class AbstractRecipeReader implements VanillaRecipeReader { - - protected String[] readPattern(JsonObject object) { - JsonArray pattern = object.getAsJsonArray("pattern"); - List patternList = new ArrayList<>(); - for (JsonElement element : pattern) { - patternList.add(element.getAsString()); - } - return patternList.toArray(new String[0]); - } - - @Nullable - protected String readGroup(JsonObject object) { - return object.has("group") ? object.get("group").getAsString() : null; - } - - @Nullable - protected CraftingRecipeCategory readCraftingCategory(JsonObject object) { - return object.has("category") ? CraftingRecipeCategory.valueOf(object.get("category").getAsString().toUpperCase(Locale.ENGLISH)) : null; - } - - @Nullable - protected CookingRecipeCategory readCookingCategory(JsonObject object) { - return object.has("category") ? CookingRecipeCategory.valueOf(object.get("category").getAsString().toUpperCase(Locale.ENGLISH)) : null; - } - - protected float readExperience(JsonObject object) { - return object.has("experience") ? object.get("experience").getAsFloat() : 0; - } - - protected int readCookingTime(JsonObject object) { - return object.has("cookingtime") ? object.get("cookingtime").getAsInt() : 200; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java deleted file mode 100644 index d45c8e5a2..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java +++ /dev/null @@ -1,206 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla.reader; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import net.momirealms.craftengine.core.item.recipe.vanilla.*; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class VanillaRecipeReader1_20 extends AbstractRecipeReader { - - @Override - public VanillaShapedRecipe readShaped(JsonObject json) { - return new VanillaShapedRecipe( - readCraftingCategory(json), - readGroup(json), - readShapedIngredientMap(json.getAsJsonObject("key")), - readPattern(json), - readCraftingResult(json.getAsJsonObject("result")) - ); - } - - @Override - public VanillaShapelessRecipe readShapeless(JsonObject json) { - return new VanillaShapelessRecipe( - readCraftingCategory(json), - readGroup(json), - readShapelessIngredients(json.getAsJsonArray("ingredients")), - readCraftingResult(json.getAsJsonObject("result")) - ); - } - - @Override - public VanillaBlastingRecipe readBlasting(JsonObject json) { - return new VanillaBlastingRecipe( - readCookingCategory(json), - readGroup(json), - readCookingResult(json.get("result")), - readSingleIngredient(json.get("ingredient")), - readExperience(json), - readCookingTime(json) - ); - } - - @Override - public VanillaSmeltingRecipe readSmelting(JsonObject json) { - return new VanillaSmeltingRecipe( - readCookingCategory(json), - readGroup(json), - readCookingResult(json.get("result")), - readSingleIngredient(json.get("ingredient")), - readExperience(json), - readCookingTime(json) - ); - } - - @Override - public VanillaSmokingRecipe readSmoking(JsonObject json) { - return new VanillaSmokingRecipe( - readCookingCategory(json), - readGroup(json), - readCookingResult(json.get("result")), - readSingleIngredient(json.get("ingredient")), - readExperience(json), - readCookingTime(json) - ); - } - - @Override - public VanillaCampfireRecipe readCampfire(JsonObject json) { - return new VanillaCampfireRecipe( - readCookingCategory(json), - readGroup(json), - readCookingResult(json.get("result")), - readSingleIngredient(json.get("ingredient")), - readExperience(json), - readCookingTime(json) - ); - } - - @Override - public VanillaStoneCuttingRecipe readStoneCutting(JsonObject json) { - return new VanillaStoneCuttingRecipe( - readGroup(json), - readStoneCuttingResult(json), - readSingleIngredient(json.get("ingredient")) - ); - } - - @Override - public VanillaSmithingTransformRecipe readSmithingTransform(JsonObject json) { - return new VanillaSmithingTransformRecipe( - readSingleIngredient(json.get("base")), - readSingleIngredient(json.get("template")), - readSingleIngredient(json.get("addition")), - readSmithingResult(json.getAsJsonObject("result")) - ); - } - - @Override - public VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json) { - return new VanillaSmithingTrimRecipe( - readSingleIngredient(json.get("base")), - readSingleIngredient(json.get("template")), - readSingleIngredient(json.get("addition")), - null - ); - } - - protected List readSingleIngredient(JsonElement json) { - List ingredients = new ArrayList<>(); - if (json.isJsonObject()) { - JsonObject argument = json.getAsJsonObject(); - if (argument.has("item")) { - ingredients.add(argument.get("item").getAsString()); - } else if (argument.has("tag")) { - ingredients.add("#" + argument.get("tag").getAsString()); - } - } else if (json.isJsonArray()) { - List items = readIngredientList((JsonArray) json); - ingredients.addAll(items); - } - return ingredients; - } - - @NotNull - protected RecipeResult readStoneCuttingResult(JsonObject json) { - int count = json.has("count") ? json.get("count").getAsInt() : 1; - String result = json.get("result").getAsString(); - return new RecipeResult(result, count, null); - } - - @NotNull - protected RecipeResult readCookingResult(JsonElement object) { - return new RecipeResult(object.getAsString(), 1, null); - } - - @NotNull - protected RecipeResult readCraftingResult(JsonObject object) { - String item = object.get("item").getAsString(); - int count = object.has("count") ? object.get("count").getAsInt() : 1; - return new RecipeResult(item, count, null); - } - - @NotNull - protected RecipeResult readSmithingResult(JsonObject object) { - String item = object.get("item").getAsString(); - return new RecipeResult(item, 1, null); - } - - protected List> readShapelessIngredients(JsonArray json) { - List> ingredients = new ArrayList<>(); - for (JsonElement element : json) { - if (element.isJsonObject()) { - JsonObject jsonObject = element.getAsJsonObject(); - if (jsonObject.has("item")) { - ingredients.add(List.of(jsonObject.get("item").getAsString())); - } else if (jsonObject.has("tag")) { - ingredients.add(List.of("#" + jsonObject.get("tag").getAsString())); - } - } else if (element.isJsonArray()) { - List ingredient = readIngredientList((JsonArray) element); - ingredients.add(ingredient); - } - } - return ingredients; - } - - protected Map> readShapedIngredientMap(JsonObject json) { - Map> ingredients = new HashMap<>(); - for (Map.Entry entry : json.entrySet()) { - char c = entry.getKey().charAt(0); - if (entry.getValue().isJsonObject()) { - JsonObject argument = entry.getValue().getAsJsonObject(); - if (argument.has("item")) { - ingredients.put(c, List.of(argument.get("item").getAsString())); - } else if (argument.has("tag")) { - ingredients.put(c, List.of("#" + argument.get("tag").getAsString())); - } - } else if (entry.getValue().isJsonArray()) { - List items = readIngredientList((JsonArray) entry.getValue()); - ingredients.put(c, items); - } - } - return ingredients; - } - - protected @NotNull List readIngredientList(JsonArray array) { - List items = new ArrayList<>(); - for (JsonElement element : array) { - if (element.isJsonObject()) { - JsonObject argument = element.getAsJsonObject(); - if (argument.has("item")) { - items.add(argument.get("item").getAsString()); - } else if (argument.has("tag")) { - items.add("#" + argument.get("tag").getAsString()); - } - } - } - return items; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20_5.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20_5.java deleted file mode 100644 index 3bd399f96..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20_5.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla.reader; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import net.momirealms.craftengine.core.item.recipe.vanilla.RecipeResult; -import org.jetbrains.annotations.NotNull; - -public class VanillaRecipeReader1_20_5 extends VanillaRecipeReader1_20 { - - @Override - protected @NotNull RecipeResult readCraftingResult(JsonObject object) { - String item = object.get("id").getAsString(); - JsonObject components = object.has("components") ? object.getAsJsonObject("components") : null; - int count = object.has("count") ? object.get("count").getAsInt() : 1; - return new RecipeResult(item, count, components); - } - - @NotNull - @Override - protected RecipeResult readCookingResult(JsonElement object) { - return readCraftingResult(object.getAsJsonObject()); - } - - @NotNull - @Override - protected RecipeResult readStoneCuttingResult(JsonObject json) { - return readCraftingResult(json.getAsJsonObject("result")); - } - - @Override - protected @NotNull RecipeResult readSmithingResult(JsonObject object) { - return readCraftingResult(object.getAsJsonObject()); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_5.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_5.java deleted file mode 100644 index 49634d90e..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_5.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla.reader; - -import com.google.gson.JsonObject; -import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaSmithingTrimRecipe; - -public class VanillaRecipeReader1_21_5 extends VanillaRecipeReader1_21_2 { - - @Override - public VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json) { - return new VanillaSmithingTrimRecipe( - readSingleIngredient(json.get("base")), - readSingleIngredient(json.get("template")), - readSingleIngredient(json.get("addition")), - json.get("pattern").getAsString() - ); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index a864ca257..fd0da1023 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -9,7 +9,8 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; -import net.momirealms.craftengine.core.item.recipe.RecipeFactory; +import net.momirealms.craftengine.core.item.recipe.Recipe; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializer; import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; @@ -63,7 +64,7 @@ public class BuiltInRegistries { public static final Registry CONDITION_PROPERTY_READER = createConstantBoundRegistry(Registries.CONDITION_PROPERTY_READER); public static final Registry SELECT_PROPERTY_FACTORY = createConstantBoundRegistry(Registries.SELECT_PROPERTY_FACTORY); public static final Registry SELECT_PROPERTY_READER = createConstantBoundRegistry(Registries.SELECT_PROPERTY_READER); - public static final Registry> RECIPE_FACTORY = createConstantBoundRegistry(Registries.RECIPE_FACTORY); + public static final Registry>> RECIPE_SERIALIZER = createConstantBoundRegistry(Registries.RECIPE_FACTORY); public static final Registry FORMULA_FACTORY = createConstantBoundRegistry(Registries.FORMULA_FACTORY); public static final Registry> PATH_MATCHER_FACTORY = createConstantBoundRegistry(Registries.PATH_MATCHER_FACTORY); public static final Registry RESOLUTION_FACTORY = createConstantBoundRegistry(Registries.RESOLUTION_FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index fe447e488..e0845e4ff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -9,7 +9,8 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; -import net.momirealms.craftengine.core.item.recipe.RecipeFactory; +import net.momirealms.craftengine.core.item.recipe.Recipe; +import net.momirealms.craftengine.core.item.recipe.RecipeSerializer; import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; @@ -65,7 +66,7 @@ public class Registries { public static final ResourceKey> CONDITION_PROPERTY_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("condition_property_reader")); public static final ResourceKey> SELECT_PROPERTY_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("select_property_factory")); public static final ResourceKey> SELECT_PROPERTY_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("select_property_reader")); - public static final ResourceKey>> RECIPE_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_factory")); + public static final ResourceKey>>> RECIPE_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_factory")); public static final ResourceKey> FORMULA_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("formula_factory")); public static final ResourceKey>> PATH_MATCHER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); public static final ResourceKey> RESOLUTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); diff --git a/gradle.properties b/gradle.properties index 837b678ab..5ac011f68 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.10 +project_version=0.0.60.10.3 config_version=43 lang_version=23 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.18 -nms_helper_version=1.0.48 +nms_helper_version=1.0.51 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 99d2d16312241420f39b8c2798e71e5bb19f3b34 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 3 Aug 2025 23:15:11 +0800 Subject: [PATCH 75/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A7=86=E8=A7=89?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/RecipeEventListener.java | 22 ++++++++++++++----- gradle.properties | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 8c2d8f75a..328ff1000 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -647,9 +647,14 @@ public class RecipeEventListener implements Listener { event.setResult(null); return; } - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); - event.setResult(result); + SmithingInput input = getSmithingInput(inventory); + if (smithingTrimRecipe.matches(input)) { + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); + ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); + event.setResult(result); + } else { + event.setResult(null); + } } @EventHandler(ignoreCancelled = true) @@ -666,9 +671,14 @@ public class RecipeEventListener implements Listener { event.setResult(null); return; } - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - ItemStack processed = smithingTransformRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); - event.setResult(processed); + SmithingInput input = getSmithingInput(inventory); + if (smithingTransformRecipe.matches(input)) { + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); + ItemStack processed = smithingTransformRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); + event.setResult(processed); + } else { + event.setResult(null); + } } private SmithingInput getSmithingInput(SmithingInventory inventory) { diff --git a/gradle.properties b/gradle.properties index 5ac011f68..458b1627b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.18 -nms_helper_version=1.0.51 +nms_helper_version=1.0.52 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From d34213cca69b1f3c26e51c5d591fa00d1e7c0995 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 3 Aug 2025 23:19:44 +0800 Subject: [PATCH 76/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=85=8D=E6=96=B9=E7=B1=BB=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/resources/default/configuration/items.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/common-files/src/main/resources/resources/default/configuration/items.yml b/common-files/src/main/resources/resources/default/configuration/items.yml index 33bc98478..b25111d18 100644 --- a/common-files/src/main/resources/resources/default/configuration/items.yml +++ b/common-files/src/main/resources/resources/default/configuration/items.yml @@ -326,6 +326,7 @@ equipments#topaz: recipes#topaz: default:topaz_shovel: type: shaped + category: equipment pattern: - A - B @@ -338,6 +339,7 @@ recipes#topaz: count: 1 default:topaz_axe: type: shaped + category: equipment pattern: - 'AA' - 'AB' @@ -350,6 +352,7 @@ recipes#topaz: count: 1 default:topaz_sword: type: shaped + category: equipment pattern: - A - A @@ -362,6 +365,7 @@ recipes#topaz: count: 1 default:topaz_hoe: type: shaped + category: equipment pattern: - 'AA' - ' B' @@ -374,6 +378,7 @@ recipes#topaz: count: 1 default:topaz_pickaxe: type: shaped + category: equipment pattern: - 'AAA' - ' B ' @@ -386,6 +391,7 @@ recipes#topaz: count: 1 default:topaz_helmet: type: shaped + category: equipment pattern: - AAA - A A @@ -396,6 +402,7 @@ recipes#topaz: count: 1 default:topaz_chestplate: type: shaped + category: equipment pattern: - A A - AAA @@ -407,6 +414,7 @@ recipes#topaz: count: 1 default:topaz_leggings: type: shaped + category: equipment pattern: - AAA - A A @@ -418,6 +426,7 @@ recipes#topaz: count: 1 default:topaz_boots: type: shaped + category: equipment pattern: - A A - A A From 75cce7f1d863b64379f55e9351c5bc9cef3c998d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 4 Aug 2025 01:38:27 +0800 Subject: [PATCH 77/83] =?UTF-8?q?=E7=BB=86=E5=BE=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/factory/BukkitItemFactory.java | 9 ++++----- .../bukkit/item/recipe/RecipeEventListener.java | 2 +- .../bukkit/plugin/injector/RecipeInjector.java | 2 +- .../bukkit/plugin/user/BukkitServerPlayer.java | 2 +- .../craftengine/bukkit/util/InteractUtils.java | 8 ++++---- .../craftengine/core/item/AbstractItem.java | 13 ++++++++----- .../net/momirealms/craftengine/core/item/Item.java | 8 +++++--- .../craftengine/core/item/ItemFactory.java | 2 +- .../momirealms/craftengine/core/util/UniqueKey.java | 2 -- gradle.properties | 2 +- 10 files changed, 26 insertions(+), 24 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index b042fe12c..19838cdc9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.ExternalItemSource; import net.momirealms.craftengine.core.item.ItemFactory; +import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.setting.EquipmentData; @@ -84,14 +85,14 @@ public abstract class BukkitItemFactory> extend @Override protected Key vanillaId(W item) { Object i = FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()); - if (i == null) return null; + if (i == null) return ItemKeys.AIR; return KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, i)); } @Override protected Key id(W item) { if (FastNMS.INSTANCE.method$ItemStack$isEmpty(item.getLiteralObject())) { - return null; + return ItemKeys.AIR; } return customId(item).orElse(vanillaId(item)); } @@ -118,14 +119,12 @@ public abstract class BukkitItemFactory> extend } @Override - protected boolean is(W item, Key itemTag) { + protected boolean hasItemTag(W item, Key itemTag) { Object literalObject = item.getLiteralObject(); Object tag = ItemTags.getOrCreate(itemTag); return FastNMS.INSTANCE.method$ItemStack$is(literalObject, tag); } - - @Override protected void setJavaComponent(W item, Object type, Object value) { throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 328ff1000..eb1004ba3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -368,7 +368,7 @@ public class RecipeEventListener implements Listener { repairItem = item; break; } - if (wrappedFirst.is(tag)) { + if (wrappedFirst.hasItemTag(tag)) { repairItem = item; break; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 623bdf0e2..208dc973a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -345,7 +345,7 @@ public class RecipeInjector { private static final Predicate> IS_DYEABLE = VersionHelper.isOrAbove1_20_5() ? - (item -> item.is(ItemTags.DYEABLE)) : + (item -> item.hasItemTag(ItemTags.DYEABLE)) : (item -> { Object itemLike = FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()); return CoreReflections.clazz$DyeableLeatherItem.isInstance(itemLike); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index fd6156d23..a2c501de6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -638,7 +638,7 @@ public class BukkitServerPlayer extends Player { if (canInstabuild() && (itemMaterial == Material.DEBUG_STICK || itemMaterial == Material.TRIDENT || (VersionHelper.isOrAbove1_20_5() && itemMaterial == MaterialUtils.MACE) - || item.is(ItemTags.SWORDS))) { + || item.hasItemTag(ItemTags.SWORDS))) { return; } } 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 ec33bb09f..34c7cf27e 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 @@ -45,7 +45,7 @@ public class InteractUtils { private InteractUtils() {} static { - registerInteraction(BlockKeys.NOTE_BLOCK, (player, item, blockState, result) -> result.getDirection() != Direction.UP || !item.is(NOTE_BLOCK_TOP_INSTRUMENTS)); + registerInteraction(BlockKeys.NOTE_BLOCK, (player, item, blockState, result) -> result.getDirection() != Direction.UP || !item.hasItemTag(NOTE_BLOCK_TOP_INSTRUMENTS)); registerInteraction(BlockKeys.CAKE, (player, item, blockState, result) -> !canEat(player, false)); registerInteraction(BlockKeys.CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); registerInteraction(BlockKeys.WHITE_CANDLE_CAKE, (player, item, blockState, result) -> !canEat(player, false)); @@ -409,14 +409,14 @@ public class InteractUtils { registerEntityInteraction(EntityTypeKeys.BAMBOO_RAFT, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityTypeKeys.MINECART, (player, entity, item) -> !player.isSneaking()); registerEntityInteraction(EntityTypeKeys.PARROT, (player, entity, item) -> { - if (item != null && item.is(Key.of("parrot_poisonous_food"))) return true; + if (item != null && item.hasItemTag(Key.of("parrot_poisonous_food"))) return true; return canFeed(entity, item) || isPetOwner(player, entity); }); registerEntityInteraction(EntityTypeKeys.HAPPY_GHAST, (player, entity, item) -> { if (item != null && item.vanillaId().equals(ItemKeys.HARNESS)) return true; if (entity instanceof HappyGhast happyGhast && !player.isSneaking()) { ItemStack bodyItem = happyGhast.getEquipment().getItem(EquipmentSlot.BODY); - return BukkitItemManager.instance().wrap(bodyItem).is(Key.of("harnesses")); + return BukkitItemManager.instance().wrap(bodyItem).hasItemTag(Key.of("harnesses")); } return canFeed(entity, item); }); @@ -499,7 +499,7 @@ public class InteractUtils { } private static boolean canFeed(Entity entity, Item item) { - return entity instanceof Animals && item.is(Key.of(EntityUtils.getEntityType(entity).value() + "_food")); + return entity instanceof Animals && item.hasItemTag(Key.of(EntityUtils.getEntityType(entity).value() + "_food")); } private static boolean hasSaddle(Player player, Entity entity) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index af97388f6..de299e7ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -8,11 +8,14 @@ import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.data.Trim; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Optional; @@ -152,17 +155,17 @@ public class AbstractItem, I> implements Item { } @Override - public Key id() { + public @NotNull Key id() { return this.factory.id(this.item); } @Override - public Key vanillaId() { + public @NotNull Key vanillaId() { return this.factory.vanillaId(this.item); } @Override - public UniqueKey recipeIngredientId() { + public @Nullable UniqueKey recipeIngredientId() { return this.factory.recipeIngredientID(this.item); } @@ -441,8 +444,8 @@ public class AbstractItem, I> implements Item { } @Override - public boolean is(Key itemTag) { - return this.factory.is(this.item, itemTag); + public boolean hasItemTag(Key itemTag) { + return this.factory.hasItemTag(this.item, itemTag); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 8e61ca095..7cb3454fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -14,9 +14,11 @@ import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Objects; import java.util.Optional; /** @@ -38,10 +40,10 @@ public interface Item { boolean isBlockItem(); - @Nullable + @NotNull Key id(); - @Nullable + @NotNull Key vanillaId(); @Nullable @@ -194,7 +196,7 @@ public interface Item { Item copyWithCount(int count); - boolean is(Key itemTag); + boolean hasItemTag(Key itemTag); Object getLiteralObject(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index 1391a199d..43de1de6f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -165,7 +165,7 @@ public abstract class ItemFactory, I> { protected abstract void maxStackSize(W item, Integer maxStackSize); - protected abstract boolean is(W item, Key itemTag); + protected abstract boolean hasItemTag(W item, Key itemTag); protected abstract boolean isBlockItem(W item); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/UniqueKey.java b/core/src/main/java/net/momirealms/craftengine/core/util/UniqueKey.java index 1a4591535..a9e023a57 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/UniqueKey.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/UniqueKey.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.util; -import net.momirealms.craftengine.core.item.ItemKeys; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -8,7 +7,6 @@ import java.util.Map; public final class UniqueKey { private static final Map CACHE = new HashMap<>(4096, 0.5f); - public static final UniqueKey AIR = UniqueKey.create(ItemKeys.AIR); private final Key key; diff --git a/gradle.properties b/gradle.properties index 458b1627b..7399a1fc1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.10.3 +project_version=0.0.60.11 config_version=43 lang_version=23 project_group=net.momirealms From 429c33b1eec9b53afb4cdd002b4c583d0cc34948 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 4 Aug 2025 12:26:34 +0800 Subject: [PATCH 78/83] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D=201.20?= =?UTF-8?q?=20~=201.20.4=20=E6=97=A0=E6=B3=95=E5=90=AF=E5=8A=A8=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/BukkitRecipeManager.java | 4 +- .../reflection/minecraft/CoreReflections.java | 5 +- .../core/item/recipe/CustomRecipeResult.java | 42 +---------------- .../postprocessor/ApplyItemDataProcessor.java | 46 +++++++++++++++++++ .../recipe/postprocessor/PostProcessors.java | 21 +++++++++ .../core/registry/BuiltInRegistries.java | 2 +- .../craftengine/core/registry/Registries.java | 2 +- 7 files changed, 76 insertions(+), 46 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 7ec945e9c..aa69741ca 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.recipe.*; +import net.momirealms.craftengine.core.item.recipe.postprocessor.PostProcessors; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -28,10 +29,8 @@ import org.bukkit.NamespacedKey; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; -import java.io.IOException; import java.io.Reader; import java.lang.reflect.Array; -import java.sql.Ref; import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -288,6 +287,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { public BukkitRecipeManager(BukkitCraftEngine plugin) { instance = this; + PostProcessors.init(); this.plugin = plugin; this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager()); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 4877f0aa3..c5b48563d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3755,11 +3755,14 @@ public final class CoreReflections { methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = ReflectionUtils.unreflectMethod(method$ServerConfigurationPacketListenerImpl$finishCurrentTask) .asType(MethodType.methodType(void.class, Object.class, Object.class)); + } else { + methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; + } + if (VersionHelper.isOrAbove1_20_5()) { methodHandle$ServerCommonPacketListenerImpl$closedSetter = ReflectionUtils.unreflectSetter(field$ServerCommonPacketListenerImpl$closed) .asType(MethodType.methodType(void.class, Object.class, boolean.class)); } else { - methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; methodHandle$ServerCommonPacketListenerImpl$closedSetter = null; } } catch (ReflectiveOperationException e) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java index aff047c53..0101cb8c9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java @@ -3,21 +3,13 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.BuildableItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Registries; -import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.ResourceKey; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import java.util.Optional; -@SuppressWarnings("unchecked") public record CustomRecipeResult(BuildableItem item, int count, PostProcessor[] postProcessors) { public T buildItemStack(ItemBuildContext context) { @@ -34,24 +26,8 @@ public record CustomRecipeResult(BuildableItem item, int count, PostProces return builtItem; } - static { - registerPostProcessorType(Key.of("apply_data"), args -> { - List> modifiers = new ArrayList<>(); - Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); - for (Map.Entry entry : data.entrySet()) { - Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), "craftengine"))) - .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); - } - return new ApplyItemDataProcessor<>(modifiers.toArray(new ItemDataModifier[0])); - }); - } - - public static void registerPostProcessorType(Key id, PostProcessor.Type type) { - ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE) - .register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); - } - @FunctionalInterface + @SuppressWarnings("unchecked") public interface PostProcessor { static PostProcessor fromMap(Map map) { @@ -71,20 +47,4 @@ public record CustomRecipeResult(BuildableItem item, int count, PostProces PostProcessor create(Map args); } } - - public static class ApplyItemDataProcessor implements PostProcessor { - private final ItemDataModifier[] modifiers; - - public ApplyItemDataProcessor(ItemDataModifier[] modifiers) { - this.modifiers = modifiers; - } - - @Override - public Item process(Item item, ItemBuildContext context) { - for (ItemDataModifier modifier : this.modifiers) { - item.apply(modifier, context); - } - return item; - } - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java new file mode 100644 index 000000000..a0feb356c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java @@ -0,0 +1,46 @@ +package net.momirealms.craftengine.core.item.recipe.postprocessor; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ApplyItemDataProcessor implements CustomRecipeResult.PostProcessor { + public static final Type TYPE = new Type<>(); + private final ItemDataModifier[] modifiers; + + public ApplyItemDataProcessor(ItemDataModifier[] modifiers) { + this.modifiers = modifiers; + } + + @Override + public Item process(Item item, ItemBuildContext context) { + for (ItemDataModifier modifier : this.modifiers) { + item.apply(modifier, context); + } + return item; + } + + public static class Type implements CustomRecipeResult.PostProcessor.Type { + + @Override + @SuppressWarnings("unchecked") + public CustomRecipeResult.PostProcessor create(Map args) { + List> modifiers = new ArrayList<>(); + Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); + for (Map.Entry entry : data.entrySet()) { + Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), "craftengine"))) + .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); + } + return new ApplyItemDataProcessor<>(modifiers.toArray(new ItemDataModifier[0])); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java new file mode 100644 index 000000000..d128e1dc0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.item.recipe.postprocessor; + +import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceKey; + +public class PostProcessors { + public static final Key APPLY_DATA = Key.of("craftengine", "apply_data"); + + public static void init() { + register(APPLY_DATA, ApplyItemDataProcessor.TYPE); + } + + public static void register(Key id, CustomRecipeResult.PostProcessor.Type type) { + ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE) + .register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index fd0da1023..4f646e4bc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -78,7 +78,7 @@ public class BuiltInRegistries { public static final Registry SLOT_DISPLAY_TYPE = createConstantBoundRegistry(Registries.SLOT_DISPLAY_TYPE); public static final Registry RECIPE_DISPLAY_TYPE = createConstantBoundRegistry(Registries.RECIPE_DISPLAY_TYPE); public static final Registry LEGACY_RECIPE_TYPE = createConstantBoundRegistry(Registries.LEGACY_RECIPE_TYPE); - public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); + public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); private static Registry createConstantBoundRegistry(ResourceKey> key) { return new ConstantBoundRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index e0845e4ff..5457cc615 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -80,5 +80,5 @@ public class Registries { public static final ResourceKey> SLOT_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("slot_display_type")); public static final ResourceKey> RECIPE_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_display_type")); public static final ResourceKey> LEGACY_RECIPE_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("legacy_recipe_type")); - public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); + public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); } From c6a325322b78e9bffb16a3cf4300f1e9955742bc Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 4 Aug 2025 12:47:25 +0800 Subject: [PATCH 79/83] =?UTF-8?q?refactor(translations):=20=E6=A0=A1?= =?UTF-8?q?=E5=AF=B9=E7=AE=80=E4=B8=AD=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/zh_cn.yml | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 77a18b454..3512ddf1b 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -59,21 +59,21 @@ command.resource.enable.failure.unknown: "未知资源 " command.resource.disable.success: "已禁用 . 执行 /ce reload all 以应用更改" command.resource.disable.failure.unknown: "未知资源 " command.resource.list: "启用的资源(): 禁用的资源(): " -command.upload.failure.not_supported: "当前托管模式 '' 不支持上传资源包." -command.upload.on_progress: "已开始上传进程. 检查控制台以获取详细信息." +command.upload.failure.not_supported: "当前托管模式 '' 不支持上传资源包" +command.upload.on_progress: "已开始上传进程. 检查控制台以获取详细信息" command.send_resource_pack.success.single: "发送资源包给 " command.send_resource_pack.success.multiple: "发送资源包给 个玩家" warning.config.pack.duplicated_files: "发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决" -warning.config.yaml.duplicated_key: "在文件 发现问题 - 在第行发现重复的键 '', 这可能会导致一些意料之外的问题." -warning.config.yaml.inconsistent_value_type: "在文件 发现问题 - 在第行发现重复且值类型不同的键 '', 这可能会导致一些意料之外的问题." +warning.config.yaml.duplicated_key: "在文件 发现问题 - 在第行发现重复的键 '', 这可能会导致一些意料之外的问题" +warning.config.yaml.inconsistent_value_type: "在文件 发现问题 - 在第行发现重复且值类型不同的键 '', 这可能会导致一些意料之外的问题" warning.config.type.int: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为整数类型 (选项 '')" -warning.config.type.float: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为浮点数类型 (选项 '')" warning.config.type.boolean: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为布尔类型 (选项 '')" +warning.config.type.float: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为浮点数类型 (选项 '')" warning.config.type.double: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为双精度类型 (选项 '')" warning.config.type.quaternionf: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为四元数类型 (选项 '')" warning.config.type.vector3f: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为三维向量类型 (选项 '')" warning.config.type.map: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为映射类型 (选项 '')" -warning.config.type.snbt.invalid_syntax: "在文件 发现问题 - 无法加载 '': 无效的 SNBT 语法 ''." +warning.config.type.snbt.invalid_syntax: "在文件 发现问题 - 无法加载 '': 无效的 SNBT 语法 ''" warning.config.number.missing_type: "在文件 发现问题 - 配置项 '' 缺少数字类型所需的 'type' 参数" warning.config.number.invalid_type: "在文件 发现问题 - 配置项 '' 使用了无效的数字类型 ''" warning.config.number.missing_argument: "在文件 发现问题 - 配置项 '' 缺少数字参数" @@ -103,11 +103,11 @@ warning.config.condition.string_contains.missing_value2: "在文件 在文件 中发现问题 - 配置项 '' 缺少 'string_regex' 条件必需的 'value' 参数" warning.config.condition.string_regex.missing_regex: "在文件 中发现问题 - 配置项 '' 缺少 'string_regex' 条件必需的 'regex' 参数" warning.config.condition.expression.missing_expression: "在文件 中发现问题 - 配置项 '' 缺少 'expression' 条件必需的 'expression' 参数" -warning.config.condition.is_null.missing_argument: "在文件 发现问题 - 配置项 '' 缺少 'is_null' 条件的必需的 'argument' 参数." -warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" +warning.config.condition.is_null.missing_argument: "在文件 发现问题 - 配置项 '' 缺少 'is_null' 条件的必需的 'argument' 参数" warning.config.condition.hand.missing_hand: "在文件 发现问题 - 配置项 '' 缺少 'hand' 条件必需的 'hand' 参数" warning.config.condition.hand.invalid_hand: "在文件 发现问题 - 配置项 '' 使用了无效的 'hand' 参数 ''('hand' 条件)。允许的手部类型: []" warning.config.condition.on_cooldown.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'on_cooldown' 条件必需的 'id' 参数" +warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" warning.config.image.height_ascent_conflict: "在文件 发现问题 - 图片 '' 违反位图规则: 'height' 参数 '' 必须不小于 'ascent' 参数 ''" @@ -141,12 +141,16 @@ warning.config.recipe.smithing_trim.missing_base: "在文件 发 warning.config.recipe.smithing_trim.missing_template_type: "在文件 发现问题 - 锻造纹饰配方 '' 缺少必需的 'template-type' 参数" warning.config.recipe.smithing_trim.missing_addition: "在文件 发现问题 - 锻造纹饰配方 '' 缺少必需的 'addition' 参数" warning.config.recipe.smithing_trim.missing_pattern: "在文件 发现问题 - 锻造纹饰配方 '' 缺少必需的 'pattern' 参数" +warning.config.recipe.brewing.missing_container: "在文件 发现问题 - 酿造配方 '' 缺少必需的 'container' 参数" +warning.config.recipe.brewing.missing_ingredient: "在文件 发现问题 - 酿造配方 '' 缺少必需的 'ingredient' 参数" +warning.config.recipe.result.post_processor.missing_type: "在文件 发现问题 - 配方 '' 缺少结果后处理器必需的 'type' 参数" +warning.config.recipe.result.post_processor.invalid_type: "在文件 发现问题 - 配方 '' 使用了无效结果后处理器类型 ''" warning.config.i18n.unknown_locale: "在文件 发现问题 - 未知的语言环境 ''" warning.config.template.duplicate: "在文件 发现问题 - 重复的模板 '' 请检查其他文件中是否存在相同配置" +warning.config.template.invalid: "在文件 发现问题 - 配置 '' 使用了无效的模板 ''" warning.config.template.argument.self_increase_int.invalid_range: "在文件 发现问题 - 模板 '' 在 'self_increase_int' 参数中使用了一个起始值 '' 大于终止值 ''" -warning.config.template.invalid: "在文件 发现问题 - 配置 '' 使用了无效的模板 ''." warning.config.template.argument.list.invalid_type: "在文件 发现问题 - 模板 '' 的 'list' 参数需要列表类型 但输入参数类型为 ''" -warning.config.template.argument.missing_value: "在文件 发现问题 - 配置 '' 缺少了 '' 必要的模板参数值. 请使用 arguments 选项进行配置或为此参数设定默认值." +warning.config.template.argument.missing_value: "在文件 发现问题 - 配置 '' 缺少了 '' 必要的模板参数值. 请使用 arguments 选项进行配置或为此参数设定默认值" warning.config.vanilla_loot.missing_type: "在文件 发现问题 - 原版战利品 '' 缺少必需的 'type' 参数" warning.config.vanilla_loot.invalid_type: "在文件 发现问题 - 原版战利品 '' 使用了无效类型 '' 允许的类型: []" warning.config.vanilla_loot.block.invalid_target: "在文件 发现问题 - 原版战利品 '' 中存在无效的方块目标 ''" @@ -164,21 +168,24 @@ warning.config.furniture.hitbox.custom.invalid_entity: "在文件 在文件 发现问题 - 重复的物品 '' 请检查其他文件中是否存在相同配置" warning.config.item.settings.unknown: "在文件 发现问题 - 物品 '' 使用了未知的设置类型 ''" warning.config.item.settings.invulnerable.invalid_damage_source: "在文件 发现问题 - 物品 '' 物品使用了未知的伤害来源类型 '' 允许的来源: []" -warning.config.item.settings.equipment.missing_asset_id: "在文件 发现问题 - 物品 '' 缺少 'equipment' 设置所需的 'asset-id' 参数." -warning.config.item.settings.equipment.invalid_asset_id: "在文件 发现问题 - 物品 '' 为 'equipment' 设置配置了无效的 'asset-id'. 这可能是因为你没有创建装备配置或是错误地拼写了 asset-id." -warning.config.item.settings.projectile.missing_item: "在文件 发现问题 - 物品 '' 缺少 'projectile' 设置所需的 'item' 参数." -warning.config.item.data.attribute_modifiers.missing_type: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'type' 参数." -warning.config.item.data.attribute_modifiers.missing_amount: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'amount' 参数." -warning.config.item.data.attribute_modifiers.missing_operation: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'operation' 参数." -warning.config.item.data.attribute_modifiers.display.missing_type: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 显示数据所需的 'type' 参数。" -warning.config.item.data.attribute_modifiers.display.missing_value: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 显示数据所需的 'value' 参数。" +warning.config.item.settings.equipment.missing_asset_id: "在文件 发现问题 - 物品 '' 缺少 'equipment' 设置所需的 'asset-id' 参数" +warning.config.item.settings.equipment.invalid_asset_id: "在文件 发现问题 - 物品 '' 为 'equipment' 设置配置了无效的 'asset-id'. 这可能是因为你没有创建装备配置或是错误地拼写了 asset-id" +warning.config.item.settings.projectile.missing_item: "在文件 发现问题 - 物品 '' 缺少 'projectile' 设置所需的 'item' 参数" +warning.config.item.data.attribute_modifiers.missing_type: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'type' 参数" +warning.config.item.data.attribute_modifiers.missing_amount: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'amount' 参数" +warning.config.item.data.attribute_modifiers.missing_operation: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'operation' 参数" +warning.config.item.data.attribute_modifiers.display.missing_type: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 显示数据所需的 'type' 参数" +warning.config.item.data.attribute_modifiers.display.missing_value: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 显示数据所需的 'value' 参数" +warning.config.item.data.external.missing_source: "在文件 发现问题 - 物品 '' 缺少 'external' 数据所需的 'source' 参数" +warning.config.item.data.external.missing_id: "在文件 发现问题 - 物品 '' 缺少 'external' 数据所需的 'id' 参数" +warning.config.item.data.external.invalid_source: "在文件 发现问题 - 物品 '' 在 'external' 数据中使用了无效的物品来源 ''" warning.config.item.missing_material: "在文件 发现问题 - 物品 '' 缺少必需的 'material' 参数" warning.config.item.invalid_material: "在文件 发现问题 - 物品 '' 使用了无效的材料类型 ''" -warning.config.item.invalid_custom_model_data: "在文件 发现问题 - 物品 '' 使用了无效的负数模型值 ''." +warning.config.item.invalid_custom_model_data: "在文件 发现问题 - 物品 '' 使用了无效的负数模型值 ''" warning.config.item.bad_custom_model_data: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 数值过大 建议使用小于 16,777,216 的值" +warning.config.item.item_model.conflict: "在文件 发现问题 - 物品 '' 使用了无效的 'item-model' 选项. 这个 item-model 已经存在对应的原版物品" warning.config.item.custom_model_data_conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" warning.config.item.invalid_component: "在文件 发现问题 - 物品 '' 使用了未知的数据组件 ''" -warning.config.item.item_model.conflict: "在文件 发现问题 - 物品 '' 使用了无效的 'item-model' 选项. 这个 item-model 已经存在对应的原版物品." warning.config.item.missing_model_id: "在文件 发现问题 - 物品 '' 缺少必需的 'custom-model-data' 或 'item-model' 参数" warning.config.item.missing_model: "在文件 中发现问题 - 物品 '' 缺少支持 1.21.4+ 资源包必需的 'model' 配置项" warning.config.item.behavior.missing_type: "在文件 发现问题 - 物品 '' 的行为配置缺少必需的 'type' 参数" @@ -206,8 +213,8 @@ warning.config.item.model.condition.missing_on_true: "在文件 warning.config.item.model.condition.missing_on_false: "在文件 发现问题 - 物品 '' 的 'minecraft:condition' 模型缺少必需的 'on-false' 参数" warning.config.item.model.condition.keybind.missing_keybind: "在文件 发现问题 - 物品 '' 的 'minecraft:keybind_down' 属性缺少必需的 'keybind' 参数" warning.config.item.model.condition.has_component.missing_component: "在文件 发现问题 - 物品 '' 的 'minecraft:has_component' 属性缺少必需的 'component' 参数" -warning.config.item.model.condition.component.missing_predicate: "在文件 发现问题 - 物品 '' 的 'minecraft:component' 属性缺少必需的 'predicate' 参数." -warning.config.item.model.condition.component.missing_value: "在文件 发现问题 - 物品 '' 的 'minecraft:component' 属性缺少必需的 'value' 参数." +warning.config.item.model.condition.component.missing_predicate: "在文件 发现问题 - 物品 '' 的 'minecraft:component' 属性缺少必需的 'predicate' 参数" +warning.config.item.model.condition.component.missing_value: "在文件 发现问题 - 物品 '' 的 'minecraft:component' 属性缺少必需的 'value' 参数/yellow>" warning.config.item.model.composite.missing_models: "在文件 发现问题 - 物品 '' 的 'minecraft:composite' 模型缺少必需的 'models' 参数" warning.config.item.model.range_dispatch.missing_property: "在文件 发现问题 - 物品 '' 的 'minecraft:range_dispatch' 模型缺少必需的 'property' 参数" warning.config.item.model.range_dispatch.invalid_property: "在文件 发现问题 - 物品 '' 的 'minecraft:range_dispatch' 模型使用了无效属性 ''" @@ -241,7 +248,7 @@ warning.config.block.missing_state: "在文件 发现问题 - warning.config.block.state.property.missing_type: "在文件 发现问题 - 方块 '' 的属性 '' 缺少必需的 'type' 参数" warning.config.block.state.property.invalid_type: "在文件 发现问题 - 方块 '' 的属性 '' 使用了无效的类型参数 ''" warning.config.block.state.property.integer.invalid_range: "在文件 发现问题 - 方块 '' 的整数属性 '' 使用了无效的范围参数 '' 正确语法: 1~2" -warning.config.block.state.property.invalid_format: "在文件 发现问题 - 方块 '' 使用了无效的方块状态属性格式 ''." +warning.config.block.state.property.invalid_format: "在文件 发现问题 - 方块 '' 使用了无效的方块状态属性格式 ''" warning.config.block.state.missing_real_id: "在文件 发现问题 - 方块 '' 的 'state' 缺少必需的 'id' 参数 该 ID 是服务端方块 ID 用于唯一标识每种方块状态类型" warning.config.block.state.missing_state: "在文件 发现问题 - 方块 '' 的 'state' 缺少必需的 'state' 参数" warning.config.block.state.missing_properties: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'properties' 段落" @@ -373,9 +380,9 @@ warning.config.function.command.missing_command: "在文件 中 warning.config.function.actionbar.missing_actionbar: "在文件 中发现问题 - 配置项 '' 缺少 'actionbar' 函数必需的 'actionbar' 参数" warning.config.function.message.missing_message: "在文件 中发现问题 - 配置项 '' 缺少 'message' 函数必需的 'message' 参数" warning.config.function.open_window.missing_gui_type: "在文件 中发现问题 - 配置项 '' 缺少 'open_window' 函数必需的 'gui-type' 参数" -warning.config.function.open_window.invalid_gui_type: "在文件 中发现问题 - 配置项 '' 为 'open_window' 函数使用了无效的 GUI 类型 . 允许的类型: []。" +warning.config.function.open_window.invalid_gui_type: "在文件 中发现问题 - 配置项 '' 为 'open_window' 函数使用了无效的 GUI 类型 . 允许的类型: []" warning.config.function.run.missing_functions: "在文件 中发现问题 - 配置项 '' 缺少 'run' 函数必需的 'functions' 参数" -warning.config.function.place_block.missing_block_state: "在文件 中发现问题 - 配置项 '' 缺少 'place_block' 函数必需的 'block-state' 参数." +warning.config.function.place_block.missing_block_state: "在文件 中发现问题 - 配置项 '' 缺少 'place_block' 函数必需的 'block-state' 参数" warning.config.function.set_food.missing_food: "在文件 中发现问题 - 配置项 '' 缺少 'set_food' 函数必需的 'food' 参数" warning.config.function.set_saturation.missing_saturation: "在文件 中发现问题 - 配置项 '' 缺少 'set_saturation' 函数必需的 'saturation' 参数" warning.config.function.play_sound.missing_sound: "在文件 中发现问题 - 配置项 '' 缺少 'play_sound' 函数必需的 'sound' 参数" @@ -405,9 +412,9 @@ warning.config.resource_pack.generation.texture_not_in_atlas: "纹理'物品''缺少模型文件: ''" warning.config.resource_pack.generation.missing_block_model: "方块状态''缺少模型文件: ''" warning.config.resource_pack.generation.missing_parent_model: "模型''找不到父级模型文件: ''" -warning.config.resource_pack.generation.malformatted_json: "Json文件 '' 格式错误." +warning.config.resource_pack.generation.malformatted_json: "Json文件 '' 格式错误" warning.config.resource_pack.generation.missing_equipment_texture: "装备 '' 缺少纹理 ''" -warning.config.resource_pack.invalid_overlay_format: "在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 ''. Overlay格式必须包含占位符 '{version}'." +warning.config.resource_pack.invalid_overlay_format: "在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 ''. Overlay格式必须包含占位符 '{version}'" warning.config.equipment.duplicate: "在文件 发现问题 - 重复的装备配置 ''。请检查其他文件中是否存在相同配置" warning.config.equipment.missing_type: "在文件 发现问题 - 装备 '' 缺少必需的 'type' 参数" warning.config.equipment.invalid_type: "在文件 发现问题 - 装备 '' 使用了无效的 'type' 参数" From e52e42273f8e33e9582bdc09ca5e8d2f8ead80b0 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 4 Aug 2025 17:12:01 +0800 Subject: [PATCH 80/83] =?UTF-8?q?Revert=20"fix(bukkit):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=201.20=20~=201.20.4=20=E6=97=A0=E6=B3=95=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E7=9A=84=E9=97=AE=E9=A2=98"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 429c33b1eec9b53afb4cdd002b4c583d0cc34948. --- .../item/recipe/BukkitRecipeManager.java | 4 +- .../reflection/minecraft/CoreReflections.java | 5 +- .../core/item/recipe/CustomRecipeResult.java | 42 ++++++++++++++++- .../postprocessor/ApplyItemDataProcessor.java | 46 ------------------- .../recipe/postprocessor/PostProcessors.java | 21 --------- .../core/registry/BuiltInRegistries.java | 2 +- .../craftengine/core/registry/Registries.java | 2 +- 7 files changed, 46 insertions(+), 76 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index aa69741ca..7ec945e9c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -19,7 +19,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.recipe.*; -import net.momirealms.craftengine.core.item.recipe.postprocessor.PostProcessors; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -29,8 +28,10 @@ import org.bukkit.NamespacedKey; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; +import java.io.IOException; import java.io.Reader; import java.lang.reflect.Array; +import java.sql.Ref; import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -287,7 +288,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { public BukkitRecipeManager(BukkitCraftEngine plugin) { instance = this; - PostProcessors.init(); this.plugin = plugin; this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager()); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index c5b48563d..4877f0aa3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3755,14 +3755,11 @@ public final class CoreReflections { methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = ReflectionUtils.unreflectMethod(method$ServerConfigurationPacketListenerImpl$finishCurrentTask) .asType(MethodType.methodType(void.class, Object.class, Object.class)); - } else { - methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; - } - if (VersionHelper.isOrAbove1_20_5()) { methodHandle$ServerCommonPacketListenerImpl$closedSetter = ReflectionUtils.unreflectSetter(field$ServerCommonPacketListenerImpl$closed) .asType(MethodType.methodType(void.class, Object.class, boolean.class)); } else { + methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; methodHandle$ServerCommonPacketListenerImpl$closedSetter = null; } } catch (ReflectiveOperationException e) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java index 0101cb8c9..aff047c53 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java @@ -3,13 +3,21 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.BuildableItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Optional; +@SuppressWarnings("unchecked") public record CustomRecipeResult(BuildableItem item, int count, PostProcessor[] postProcessors) { public T buildItemStack(ItemBuildContext context) { @@ -26,8 +34,24 @@ public record CustomRecipeResult(BuildableItem item, int count, PostProces return builtItem; } + static { + registerPostProcessorType(Key.of("apply_data"), args -> { + List> modifiers = new ArrayList<>(); + Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); + for (Map.Entry entry : data.entrySet()) { + Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), "craftengine"))) + .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); + } + return new ApplyItemDataProcessor<>(modifiers.toArray(new ItemDataModifier[0])); + }); + } + + public static void registerPostProcessorType(Key id, PostProcessor.Type type) { + ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE) + .register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); + } + @FunctionalInterface - @SuppressWarnings("unchecked") public interface PostProcessor { static PostProcessor fromMap(Map map) { @@ -47,4 +71,20 @@ public record CustomRecipeResult(BuildableItem item, int count, PostProces PostProcessor create(Map args); } } + + public static class ApplyItemDataProcessor implements PostProcessor { + private final ItemDataModifier[] modifiers; + + public ApplyItemDataProcessor(ItemDataModifier[] modifiers) { + this.modifiers = modifiers; + } + + @Override + public Item process(Item item, ItemBuildContext context) { + for (ItemDataModifier modifier : this.modifiers) { + item.apply(modifier, context); + } + return item; + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java deleted file mode 100644 index a0feb356c..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/ApplyItemDataProcessor.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.postprocessor; - -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -public class ApplyItemDataProcessor implements CustomRecipeResult.PostProcessor { - public static final Type TYPE = new Type<>(); - private final ItemDataModifier[] modifiers; - - public ApplyItemDataProcessor(ItemDataModifier[] modifiers) { - this.modifiers = modifiers; - } - - @Override - public Item process(Item item, ItemBuildContext context) { - for (ItemDataModifier modifier : this.modifiers) { - item.apply(modifier, context); - } - return item; - } - - public static class Type implements CustomRecipeResult.PostProcessor.Type { - - @Override - @SuppressWarnings("unchecked") - public CustomRecipeResult.PostProcessor create(Map args) { - List> modifiers = new ArrayList<>(); - Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); - for (Map.Entry entry : data.entrySet()) { - Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), "craftengine"))) - .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); - } - return new ApplyItemDataProcessor<>(modifiers.toArray(new ItemDataModifier[0])); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java deleted file mode 100644 index d128e1dc0..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/postprocessor/PostProcessors.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.postprocessor; - -import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Registries; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceKey; - -public class PostProcessors { - public static final Key APPLY_DATA = Key.of("craftengine", "apply_data"); - - public static void init() { - register(APPLY_DATA, ApplyItemDataProcessor.TYPE); - } - - public static void register(Key id, CustomRecipeResult.PostProcessor.Type type) { - ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE) - .register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 4f646e4bc..fd0da1023 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -78,7 +78,7 @@ public class BuiltInRegistries { public static final Registry SLOT_DISPLAY_TYPE = createConstantBoundRegistry(Registries.SLOT_DISPLAY_TYPE); public static final Registry RECIPE_DISPLAY_TYPE = createConstantBoundRegistry(Registries.RECIPE_DISPLAY_TYPE); public static final Registry LEGACY_RECIPE_TYPE = createConstantBoundRegistry(Registries.LEGACY_RECIPE_TYPE); - public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); + public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); private static Registry createConstantBoundRegistry(ResourceKey> key) { return new ConstantBoundRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 5457cc615..e0845e4ff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -80,5 +80,5 @@ public class Registries { public static final ResourceKey> SLOT_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("slot_display_type")); public static final ResourceKey> RECIPE_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_display_type")); public static final ResourceKey> LEGACY_RECIPE_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("legacy_recipe_type")); - public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); + public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); } From fd62f69ec26a2b5702acf3013e123b88f00919d0 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 4 Aug 2025 17:13:02 +0800 Subject: [PATCH 81/83] =?UTF-8?q?=E6=92=A4=E9=94=80=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/reflection/minecraft/CoreReflections.java | 5 ++++- .../craftengine/core/item/recipe/CustomRecipeResult.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 4877f0aa3..c5b48563d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3755,11 +3755,14 @@ public final class CoreReflections { methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = ReflectionUtils.unreflectMethod(method$ServerConfigurationPacketListenerImpl$finishCurrentTask) .asType(MethodType.methodType(void.class, Object.class, Object.class)); + } else { + methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; + } + if (VersionHelper.isOrAbove1_20_5()) { methodHandle$ServerCommonPacketListenerImpl$closedSetter = ReflectionUtils.unreflectSetter(field$ServerCommonPacketListenerImpl$closed) .asType(MethodType.methodType(void.class, Object.class, boolean.class)); } else { - methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; methodHandle$ServerCommonPacketListenerImpl$closedSetter = null; } } catch (ReflectiveOperationException e) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java index aff047c53..db7caeed0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java @@ -35,7 +35,7 @@ public record CustomRecipeResult(BuildableItem item, int count, PostProces } static { - registerPostProcessorType(Key.of("apply_data"), args -> { + registerPostProcessorType(Key.of("craftengine", "apply_data"), args -> { List> modifiers = new ArrayList<>(); Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); for (Map.Entry entry : data.entrySet()) { From 85012f7058960c485dad89394e66af1ff630a5f2 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 4 Aug 2025 17:29:53 +0800 Subject: [PATCH 82/83] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E5=8E=9F=E7=89=88=E9=85=8D=E6=96=B9=E8=AF=BB=E5=8F=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/BukkitRecipeManager.java | 2 - .../bukkit/pack/BukkitPackManager.java | 2 - .../bukkit/world/BukkitWorldManager.java | 1 - .../craftengine/core/item/AbstractItem.java | 1 - .../craftengine/core/item/Item.java | 1 - .../item/recipe/AbstractGroupedRecipe.java | 6 +-- .../item/recipe/AbstractRecipeSerializer.java | 14 +++--- .../item/recipe/CustomBlastingRecipe.java | 2 +- .../core/item/recipe/CustomBrewingRecipe.java | 6 +-- .../item/recipe/CustomCampfireRecipe.java | 2 +- .../core/item/recipe/CustomCookingRecipe.java | 4 +- .../recipe/CustomCraftingTableRecipe.java | 2 +- .../core/item/recipe/CustomShapedRecipe.java | 2 +- .../item/recipe/CustomShapelessRecipe.java | 2 +- .../item/recipe/CustomSmeltingRecipe.java | 2 +- .../recipe/CustomSmithingTransformRecipe.java | 6 +-- .../core/item/recipe/CustomSmokingRecipe.java | 2 +- .../item/recipe/CustomStoneCuttingRecipe.java | 2 +- .../core/item/recipe/FixedResultRecipe.java | 2 +- ...ipeResult.java => SimpleRecipeResult.java} | 2 +- .../VanillaRecipeReader.java | 2 +- .../reader/VanillaRecipeReader1_20.java | 1 - .../recipe/vanilla/VanillaBlastingRecipe.java | 20 --------- .../recipe/vanilla/VanillaCampfireRecipe.java | 20 --------- .../recipe/vanilla/VanillaCookingRecipe.java | 37 --------------- .../recipe/vanilla/VanillaCraftingRecipe.java | 17 ------- .../recipe/vanilla/VanillaGroupedRecipe.java | 21 --------- .../item/recipe/vanilla/VanillaRecipe.java | 8 ---- .../recipe/vanilla/VanillaShapedRecipe.java | 37 --------------- .../vanilla/VanillaShapelessRecipe.java | 26 ----------- .../recipe/vanilla/VanillaSmeltingRecipe.java | 20 --------- .../VanillaSmithingTransformRecipe.java | 42 ----------------- .../vanilla/VanillaSmithingTrimRecipe.java | 45 ------------------- .../recipe/vanilla/VanillaSmokingRecipe.java | 20 --------- .../vanilla/VanillaStoneCuttingRecipe.java | 25 ----------- .../core/registry/BuiltInRegistries.java | 4 +- .../craftengine/core/registry/Registries.java | 4 +- 37 files changed, 33 insertions(+), 379 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/item/recipe/{CustomRecipeResult.java => SimpleRecipeResult.java} (98%) rename core/src/main/java/net/momirealms/craftengine/core/item/recipe/{vanilla => reader}/VanillaRecipeReader.java (95%) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 7ec945e9c..bcbe55a26 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -28,10 +28,8 @@ import org.bukkit.NamespacedKey; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; -import java.io.IOException; import java.io.Reader; import java.lang.reflect.Array; -import java.sql.Ref; import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index bad128c87..0cea939f3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.pack; import net.momirealms.craftengine.bukkit.api.event.AsyncResourcePackGenerateEvent; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.command.feature.ReloadCommand; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.ResourcePackUtils; @@ -22,7 +21,6 @@ import org.bukkit.event.player.PlayerJoinEvent; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; public class BukkitPackManager extends AbstractPackManager implements Listener { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index e4d090bad..7d557cd21 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.injector.RecipeInjector; import net.momirealms.craftengine.bukkit.plugin.injector.WorldStorageInjector; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index de299e7ac..3f7a75d8f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -8,7 +8,6 @@ import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.data.Trim; -import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 7cb3454fa..69c9a68f8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -18,7 +18,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.Objects; import java.util.Optional; /** diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java index 9af70aabb..226ebb3ec 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java @@ -7,9 +7,9 @@ import org.jetbrains.annotations.Nullable; public abstract class AbstractGroupedRecipe implements FixedResultRecipe { protected final String group; protected final Key id; - protected final CustomRecipeResult result; + protected final SimpleRecipeResult result; - protected AbstractGroupedRecipe(Key id, String group, CustomRecipeResult result) { + protected AbstractGroupedRecipe(Key id, String group, SimpleRecipeResult result) { this.group = group == null ? "" : group; this.id = id; this.result = result; @@ -31,7 +31,7 @@ public abstract class AbstractGroupedRecipe implements FixedResultRecipe { } @Override - public CustomRecipeResult result() { + public SimpleRecipeResult result() { return this.result; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index 4c17b43a1..257bb938a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -4,10 +4,10 @@ import net.momirealms.craftengine.core.item.CloneableConstantItem; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemManager; +import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20_5; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_21_2; -import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; @@ -58,25 +58,25 @@ public abstract class AbstractRecipeSerializer> implement } @SuppressWarnings({"unchecked", "rawtypes"}) - protected CustomRecipeResult parseResult(Map arguments) { + protected SimpleRecipeResult parseResult(Map arguments) { Map resultMap = MiscUtils.castToMap(arguments.get("result"), true); if (resultMap == null) { throw new LocalizedResourceConfigException("warning.config.recipe.missing_result"); } String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(resultMap.get("id"), "warning.config.recipe.result.missing_id"); int count = ResourceConfigUtils.getAsInt(resultMap.getOrDefault("count", 1), "count"); - List> processors = ResourceConfigUtils.parseConfigAsList(resultMap.get("post-processors"), CustomRecipeResult.PostProcessor::fromMap); - return new CustomRecipeResult( + List> processors = ResourceConfigUtils.parseConfigAsList(resultMap.get("post-processors"), SimpleRecipeResult.PostProcessor::fromMap); + return new SimpleRecipeResult( CraftEngine.instance().itemManager().getBuildableItem(Key.of(id)).orElseThrow(() -> new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id)), count, - processors.isEmpty() ? null : processors.toArray(new CustomRecipeResult.PostProcessor[0]) + processors.isEmpty() ? null : processors.toArray(new SimpleRecipeResult.PostProcessor[0]) ); } @SuppressWarnings("unchecked") - protected CustomRecipeResult parseResult(DatapackRecipeResult recipeResult) { + protected SimpleRecipeResult parseResult(DatapackRecipeResult recipeResult) { Item result = (Item) CraftEngine.instance().itemManager().build(recipeResult); - return new CustomRecipeResult<>(CloneableConstantItem.of(result), recipeResult.count(), null); + return new SimpleRecipeResult<>(CloneableConstantItem.of(result), recipeResult.count(), null); } @Nullable diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java index 3dcf683e7..937954b43 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java @@ -10,7 +10,7 @@ import java.util.Map; public class CustomBlastingRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomBlastingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { + public CustomBlastingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java index 994af19c4..41b621e5e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java @@ -19,12 +19,12 @@ public class CustomBrewingRecipe implements FixedResultRecipe { private final Key id; private final Ingredient container; private final Ingredient ingredient; - private final CustomRecipeResult result; + private final SimpleRecipeResult result; public CustomBrewingRecipe(@NotNull Key id, @NotNull Ingredient container, @NotNull Ingredient ingredient, - @NotNull CustomRecipeResult result) { + @NotNull SimpleRecipeResult result) { this.id = id; this.container = container; this.ingredient = ingredient; @@ -32,7 +32,7 @@ public class CustomBrewingRecipe implements FixedResultRecipe { } @Override - public CustomRecipeResult result() { + public SimpleRecipeResult result() { return this.result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java index de0afd5a6..3ccde065f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java @@ -10,7 +10,7 @@ import java.util.Map; public class CustomCampfireRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomCampfireRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { + public CustomCampfireRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java index 87847a545..a29aace6e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java @@ -18,7 +18,7 @@ public abstract class CustomCookingRecipe extends AbstractGroupedRecipe { Ingredient ingredient, int cookingTime, float experience, - CustomRecipeResult result) { + SimpleRecipeResult result) { super(id, group, result); this.category = category == null ? CookingRecipeCategory.MISC : category; this.ingredient = ingredient; @@ -40,7 +40,7 @@ public abstract class CustomCookingRecipe extends AbstractGroupedRecipe { return ingredient; } - public CustomRecipeResult result() { + public SimpleRecipeResult result() { return result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java index 9eb9153d4..34f7618de 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.util.Key; public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe { protected final CraftingRecipeCategory category; - protected CustomCraftingTableRecipe(Key id, CraftingRecipeCategory category, String group, CustomRecipeResult result) { + protected CustomCraftingTableRecipe(Key id, CraftingRecipeCategory category, String group, SimpleRecipeResult result) { super(id, group, result); this.category = category == null ? CraftingRecipeCategory.MISC : category; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java index 4e7d62a5d..7f6cd7135 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java @@ -17,7 +17,7 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { private final ParsedPattern parsedPattern; private final Pattern pattern; - public CustomShapedRecipe(Key id, CraftingRecipeCategory category, String group, Pattern pattern, CustomRecipeResult result) { + public CustomShapedRecipe(Key id, CraftingRecipeCategory category, String group, Pattern pattern, SimpleRecipeResult result) { super(id, category, group, result); this.pattern = pattern; this.parsedPattern = pattern.parse(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java index 9449ec83f..786e7f937 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java @@ -16,7 +16,7 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { private final List> ingredients; private final PlacementInfo placementInfo; - public CustomShapelessRecipe(Key id, CraftingRecipeCategory category, String group, List> ingredients, CustomRecipeResult result) { + public CustomShapelessRecipe(Key id, CraftingRecipeCategory category, String group, List> ingredients, SimpleRecipeResult result) { super(id, category, group, result); this.ingredients = ingredients; this.placementInfo = PlacementInfo.create(ingredients); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java index 2b03dec6e..bc564c379 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java @@ -10,7 +10,7 @@ import java.util.Map; public class CustomSmeltingRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomSmeltingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { + public CustomSmeltingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index f1134f90f..24ff7b8a3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -22,7 +22,7 @@ import java.util.Objects; public class CustomSmithingTransformRecipe implements FixedResultRecipe { public static final Serializer SERIALIZER = new Serializer<>(); private final Key id; - private final CustomRecipeResult result; + private final SimpleRecipeResult result; private final Ingredient base; private final Ingredient template; private final Ingredient addition; @@ -33,7 +33,7 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { @NotNull Ingredient base, @Nullable Ingredient template, @Nullable Ingredient addition, - CustomRecipeResult result, + SimpleRecipeResult result, boolean mergeComponents, List processors ) { @@ -116,7 +116,7 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { return finalResult.getItem(); } - public CustomRecipeResult result() { + public SimpleRecipeResult result() { return this.result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java index e59d341de..df7e682e3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java @@ -10,7 +10,7 @@ import java.util.Map; public class CustomSmokingRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomSmokingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { + public CustomSmokingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java index 3bc3a14e9..b3d517c4b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java @@ -13,7 +13,7 @@ public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { public static final Serializer SERIALIZER = new Serializer<>(); protected final Ingredient ingredient; - public CustomStoneCuttingRecipe(Key id, String group, Ingredient ingredient, CustomRecipeResult result) { + public CustomStoneCuttingRecipe(Key id, String group, Ingredient ingredient, SimpleRecipeResult result) { super(id, group, result); this.ingredient = ingredient; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java index 6a17c507c..3bbd1e6f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java @@ -7,7 +7,7 @@ public interface FixedResultRecipe extends Recipe { T result(ItemBuildContext context); - CustomRecipeResult result(); + SimpleRecipeResult result(); @Override default T assemble(RecipeInput input, ItemBuildContext context) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/SimpleRecipeResult.java similarity index 98% rename from core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java rename to core/src/main/java/net/momirealms/craftengine/core/item/recipe/SimpleRecipeResult.java index db7caeed0..5ce0ad88f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomRecipeResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/SimpleRecipeResult.java @@ -18,7 +18,7 @@ import java.util.Map; import java.util.Optional; @SuppressWarnings("unchecked") -public record CustomRecipeResult(BuildableItem item, int count, PostProcessor[] postProcessors) { +public record SimpleRecipeResult(BuildableItem item, int count, PostProcessor[] postProcessors) { public T buildItemStack(ItemBuildContext context) { return buildItem(context).getItem(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader.java similarity index 95% rename from core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java rename to core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader.java index 4b09b88c0..3f5e432d9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; +package net.momirealms.craftengine.core.item.recipe.reader; import com.google.gson.JsonArray; import com.google.gson.JsonElement; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java index 4cf75aa23..4a34fd17d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/reader/VanillaRecipeReader1_20.java @@ -6,7 +6,6 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java deleted file mode 100644 index 9a81d0698..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaBlastingRecipe.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; - -public class VanillaBlastingRecipe extends VanillaCookingRecipe { - - public VanillaBlastingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { - super(category, group, result, ingredient, experience, cookingTime); - } - - @Override - public Key type() { - return RecipeSerializers.BLASTING; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java deleted file mode 100644 index ae53346b0..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCampfireRecipe.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; - -public class VanillaCampfireRecipe extends VanillaCookingRecipe { - - public VanillaCampfireRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { - super(category, group, result, ingredient, experience, cookingTime); - } - - @Override - public Key type() { - return RecipeSerializers.CAMPFIRE_COOKING; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java deleted file mode 100644 index a87f385f7..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCookingRecipe.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; - -import java.util.List; - -public abstract class VanillaCookingRecipe extends VanillaGroupedRecipe { - protected final List ingredient; - protected final CookingRecipeCategory category; - protected final float experience; - protected final int cookingTime; - - protected VanillaCookingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { - super(group, result); - this.ingredient = ingredient; - this.experience = experience; - this.cookingTime = cookingTime; - this.category = category; - } - - public CookingRecipeCategory category() { - return category; - } - - public List ingredient() { - return ingredient; - } - - public float experience() { - return experience; - } - - public int cookingTime() { - return cookingTime; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java deleted file mode 100644 index 80b19b799..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaCraftingRecipe.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; - -public abstract class VanillaCraftingRecipe extends VanillaGroupedRecipe { - protected final CraftingRecipeCategory category; - - protected VanillaCraftingRecipe(CraftingRecipeCategory category, String group, DatapackRecipeResult result) { - super(group, result); - this.category = category; - } - - public CraftingRecipeCategory category() { - return category; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java deleted file mode 100644 index 0e3c3c81b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; - -public abstract class VanillaGroupedRecipe implements VanillaRecipe { - protected final String group; - protected final DatapackRecipeResult result; - - protected VanillaGroupedRecipe(String group, DatapackRecipeResult result) { - this.group = group; - this.result = result; - } - - public String group() { - return group; - } - - public DatapackRecipeResult result() { - return result; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java deleted file mode 100644 index a58cc6523..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.util.Key; - -public interface VanillaRecipe { - - Key type(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java deleted file mode 100644 index 7b40adea4..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapedRecipe.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; -import java.util.Map; - -public class VanillaShapedRecipe extends VanillaCraftingRecipe { - private final String[] pattern; - private final Map> key; - - public VanillaShapedRecipe(CraftingRecipeCategory category, - String group, - Map> key, - String[] pattern, - DatapackRecipeResult result) { - super(category, group, result); - this.key = key; - this.pattern = pattern; - } - - public Map> ingredients() { - return key; - } - - public String[] pattern() { - return pattern; - } - - @Override - public Key type() { - return RecipeSerializers.SHAPED; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java deleted file mode 100644 index 54e9a01ba..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaShapelessRecipe.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; - -public class VanillaShapelessRecipe extends VanillaCraftingRecipe { - private final List> ingredients; - - public VanillaShapelessRecipe(CraftingRecipeCategory category, String group, List> ingredients, DatapackRecipeResult result) { - super(category, group, result); - this.ingredients = ingredients; - } - - public List> ingredients() { - return ingredients; - } - - @Override - public Key type() { - return RecipeSerializers.SHAPELESS; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java deleted file mode 100644 index f5bca29dc..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmeltingRecipe.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; - -public class VanillaSmeltingRecipe extends VanillaCookingRecipe { - - public VanillaSmeltingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { - super(category, group, result, ingredient, experience, cookingTime); - } - - @Override - public Key type() { - return RecipeSerializers.SMELTING; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java deleted file mode 100644 index 8452b3f22..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; - -public class VanillaSmithingTransformRecipe implements VanillaRecipe { - private final DatapackRecipeResult result; - private final List base; - private final List template; - private final List addition; - - public VanillaSmithingTransformRecipe(List base, List template, List addition, DatapackRecipeResult result) { - this.result = result; - this.base = base; - this.template = template; - this.addition = addition; - } - - @Override - public Key type() { - return RecipeSerializers.SMITHING_TRANSFORM; - } - - public DatapackRecipeResult result() { - return result; - } - - public List base() { - return base; - } - - public List template() { - return template; - } - - public List addition() { - return addition; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java deleted file mode 100644 index 432b131c2..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public class VanillaSmithingTrimRecipe implements VanillaRecipe { - @Nullable // 1.21.5 - private final String pattern; - - private final List base; - private final List template; - private final List addition; - - public VanillaSmithingTrimRecipe(List base, List template, List addition, @Nullable String pattern) { - this.base = base; - this.template = template; - this.addition = addition; - this.pattern = pattern; - } - - @Override - public Key type() { - return RecipeSerializers.SMITHING_TRIM; - } - - public List base() { - return base; - } - - public List template() { - return template; - } - - public List addition() { - return addition; - } - - @Nullable - public String pattern() { - return pattern; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java deleted file mode 100644 index cc22dea5c..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; - -public class VanillaSmokingRecipe extends VanillaCookingRecipe { - - public VanillaSmokingRecipe(CookingRecipeCategory category, String group, DatapackRecipeResult result, List ingredient, float experience, int cookingTime) { - super(category, group, result, ingredient, experience, cookingTime); - } - - @Override - public Key type() { - return RecipeSerializers.SMOKING; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java deleted file mode 100644 index a273f5e04..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaStoneCuttingRecipe.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.vanilla; - -import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; -import net.momirealms.craftengine.core.item.recipe.RecipeSerializers; -import net.momirealms.craftengine.core.util.Key; - -import java.util.List; - -public class VanillaStoneCuttingRecipe extends VanillaGroupedRecipe { - private final List ingredient; - - public VanillaStoneCuttingRecipe(String group, DatapackRecipeResult result, List ingredient) { - super(group, result); - this.ingredient = ingredient; - } - - public List ingredient() { - return ingredient; - } - - @Override - public Key type() { - return RecipeSerializers.STONECUTTING; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index fd0da1023..061c5d4fc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -7,10 +7,10 @@ import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; -import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeSerializer; +import net.momirealms.craftengine.core.item.recipe.SimpleRecipeResult; import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; @@ -78,7 +78,7 @@ public class BuiltInRegistries { public static final Registry SLOT_DISPLAY_TYPE = createConstantBoundRegistry(Registries.SLOT_DISPLAY_TYPE); public static final Registry RECIPE_DISPLAY_TYPE = createConstantBoundRegistry(Registries.RECIPE_DISPLAY_TYPE); public static final Registry LEGACY_RECIPE_TYPE = createConstantBoundRegistry(Registries.LEGACY_RECIPE_TYPE); - public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); + public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); private static Registry createConstantBoundRegistry(ResourceKey> key) { return new ConstantBoundRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index e0845e4ff..291233df3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -7,10 +7,10 @@ import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; -import net.momirealms.craftengine.core.item.recipe.CustomRecipeResult; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeSerializer; +import net.momirealms.craftengine.core.item.recipe.SimpleRecipeResult; import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; @@ -80,5 +80,5 @@ public class Registries { public static final ResourceKey> SLOT_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("slot_display_type")); public static final ResourceKey> RECIPE_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_display_type")); public static final ResourceKey> LEGACY_RECIPE_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("legacy_recipe_type")); - public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); + public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); } From cceff15588d1cf1ff6e4abaad51dd3fced2d31da Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 4 Aug 2025 18:06:26 +0800 Subject: [PATCH 83/83] =?UTF-8?q?=E4=BF=AE=E6=94=B9post=20processors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/AbstractGroupedRecipe.java | 7 +- .../item/recipe/AbstractRecipeSerializer.java | 17 ++-- .../item/recipe/CustomBlastingRecipe.java | 3 +- .../core/item/recipe/CustomBrewingRecipe.java | 7 +- .../item/recipe/CustomCampfireRecipe.java | 3 +- .../core/item/recipe/CustomCookingRecipe.java | 5 +- .../recipe/CustomCraftingTableRecipe.java | 3 +- .../core/item/recipe/CustomShapedRecipe.java | 3 +- .../item/recipe/CustomShapelessRecipe.java | 3 +- .../item/recipe/CustomSmeltingRecipe.java | 3 +- .../recipe/CustomSmithingTransformRecipe.java | 7 +- .../core/item/recipe/CustomSmokingRecipe.java | 3 +- .../item/recipe/CustomStoneCuttingRecipe.java | 3 +- .../core/item/recipe/FixedResultRecipe.java | 5 +- .../core/item/recipe/SimpleRecipeResult.java | 90 ------------------- .../result/ApplyItemDataPostProcessor.java | 21 +++++ .../recipe/result/CustomRecipeResult.java | 22 +++++ .../item/recipe/result/PostProcessor.java | 16 ++++ .../item/recipe/result/PostProcessors.java | 47 ++++++++++ .../core/registry/BuiltInRegistries.java | 4 +- .../craftengine/core/registry/Registries.java | 4 +- 21 files changed, 155 insertions(+), 121 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/SimpleRecipeResult.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/ApplyItemDataPostProcessor.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/CustomRecipeResult.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessor.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessors.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java index 226ebb3ec..c0634f467 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java @@ -1,15 +1,16 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; public abstract class AbstractGroupedRecipe implements FixedResultRecipe { protected final String group; protected final Key id; - protected final SimpleRecipeResult result; + protected final CustomRecipeResult result; - protected AbstractGroupedRecipe(Key id, String group, SimpleRecipeResult result) { + protected AbstractGroupedRecipe(Key id, String group, CustomRecipeResult result) { this.group = group == null ? "" : group; this.id = id; this.result = result; @@ -31,7 +32,7 @@ public abstract class AbstractGroupedRecipe implements FixedResultRecipe { } @Override - public SimpleRecipeResult result() { + public CustomRecipeResult result() { return this.result; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index 257bb938a..ddb4b0e4c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -8,6 +8,9 @@ import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20_5; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_21_2; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; +import net.momirealms.craftengine.core.item.recipe.result.PostProcessor; +import net.momirealms.craftengine.core.item.recipe.result.PostProcessors; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; @@ -57,26 +60,26 @@ public abstract class AbstractRecipeSerializer> implement return recipeCategory; } - @SuppressWarnings({"unchecked", "rawtypes"}) - protected SimpleRecipeResult parseResult(Map arguments) { + @SuppressWarnings({"unchecked"}) + protected CustomRecipeResult parseResult(Map arguments) { Map resultMap = MiscUtils.castToMap(arguments.get("result"), true); if (resultMap == null) { throw new LocalizedResourceConfigException("warning.config.recipe.missing_result"); } String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(resultMap.get("id"), "warning.config.recipe.result.missing_id"); int count = ResourceConfigUtils.getAsInt(resultMap.getOrDefault("count", 1), "count"); - List> processors = ResourceConfigUtils.parseConfigAsList(resultMap.get("post-processors"), SimpleRecipeResult.PostProcessor::fromMap); - return new SimpleRecipeResult( + List> processors = ResourceConfigUtils.parseConfigAsList(resultMap.get("post-processors"), PostProcessors::fromMap); + return (CustomRecipeResult) new CustomRecipeResult<>( CraftEngine.instance().itemManager().getBuildableItem(Key.of(id)).orElseThrow(() -> new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id)), count, - processors.isEmpty() ? null : processors.toArray(new SimpleRecipeResult.PostProcessor[0]) + processors.isEmpty() ? null : processors.toArray(new PostProcessor[0]) ); } @SuppressWarnings("unchecked") - protected SimpleRecipeResult parseResult(DatapackRecipeResult recipeResult) { + protected CustomRecipeResult parseResult(DatapackRecipeResult recipeResult) { Item result = (Item) CraftEngine.instance().itemManager().build(recipeResult); - return new SimpleRecipeResult<>(CloneableConstantItem.of(result), recipeResult.count(), null); + return new CustomRecipeResult<>(CloneableConstantItem.of(result), recipeResult.count(), null); } @Nullable diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java index 937954b43..eaff6e37a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.NotNull; @@ -10,7 +11,7 @@ import java.util.Map; public class CustomBlastingRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomBlastingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { + public CustomBlastingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java index 41b621e5e..38e349063 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.input.BrewingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -19,12 +20,12 @@ public class CustomBrewingRecipe implements FixedResultRecipe { private final Key id; private final Ingredient container; private final Ingredient ingredient; - private final SimpleRecipeResult result; + private final CustomRecipeResult result; public CustomBrewingRecipe(@NotNull Key id, @NotNull Ingredient container, @NotNull Ingredient ingredient, - @NotNull SimpleRecipeResult result) { + @NotNull CustomRecipeResult result) { this.id = id; this.container = container; this.ingredient = ingredient; @@ -32,7 +33,7 @@ public class CustomBrewingRecipe implements FixedResultRecipe { } @Override - public SimpleRecipeResult result() { + public CustomRecipeResult result() { return this.result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java index 3ccde065f..9522de1fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.NotNull; @@ -10,7 +11,7 @@ import java.util.Map; public class CustomCampfireRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomCampfireRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { + public CustomCampfireRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java index a29aace6e..78009eab6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCookingRecipe.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -18,7 +19,7 @@ public abstract class CustomCookingRecipe extends AbstractGroupedRecipe { Ingredient ingredient, int cookingTime, float experience, - SimpleRecipeResult result) { + CustomRecipeResult result) { super(id, group, result); this.category = category == null ? CookingRecipeCategory.MISC : category; this.ingredient = ingredient; @@ -40,7 +41,7 @@ public abstract class CustomCookingRecipe extends AbstractGroupedRecipe { return ingredient; } - public SimpleRecipeResult result() { + public CustomRecipeResult result() { return result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java index 34f7618de..be75eede6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.core.item.recipe; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe { protected final CraftingRecipeCategory category; - protected CustomCraftingTableRecipe(Key id, CraftingRecipeCategory category, String group, SimpleRecipeResult result) { + protected CustomCraftingTableRecipe(Key id, CraftingRecipeCategory category, String group, CustomRecipeResult result) { super(id, group, result); this.category = category == null ? CraftingRecipeCategory.MISC : category; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java index 7f6cd7135..806beee76 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java @@ -4,6 +4,7 @@ import com.google.common.collect.Maps; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -17,7 +18,7 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { private final ParsedPattern parsedPattern; private final Pattern pattern; - public CustomShapedRecipe(Key id, CraftingRecipeCategory category, String group, Pattern pattern, SimpleRecipeResult result) { + public CustomShapedRecipe(Key id, CraftingRecipeCategory category, String group, Pattern pattern, CustomRecipeResult result) { super(id, category, group, result); this.pattern = pattern; this.parsedPattern = pattern.parse(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java index 786e7f937..16637d5bd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.item.recipe; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.jetbrains.annotations.NotNull; @@ -16,7 +17,7 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { private final List> ingredients; private final PlacementInfo placementInfo; - public CustomShapelessRecipe(Key id, CraftingRecipeCategory category, String group, List> ingredients, SimpleRecipeResult result) { + public CustomShapelessRecipe(Key id, CraftingRecipeCategory category, String group, List> ingredients, CustomRecipeResult result) { super(id, category, group, result); this.ingredients = ingredients; this.placementInfo = PlacementInfo.create(ingredients); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java index bc564c379..7cadcc45c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.NotNull; @@ -10,7 +11,7 @@ import java.util.Map; public class CustomSmeltingRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomSmeltingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { + public CustomSmeltingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index 24ff7b8a3..c73ac1b6e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -22,7 +23,7 @@ import java.util.Objects; public class CustomSmithingTransformRecipe implements FixedResultRecipe { public static final Serializer SERIALIZER = new Serializer<>(); private final Key id; - private final SimpleRecipeResult result; + private final CustomRecipeResult result; private final Ingredient base; private final Ingredient template; private final Ingredient addition; @@ -33,7 +34,7 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { @NotNull Ingredient base, @Nullable Ingredient template, @Nullable Ingredient addition, - SimpleRecipeResult result, + CustomRecipeResult result, boolean mergeComponents, List processors ) { @@ -116,7 +117,7 @@ public class CustomSmithingTransformRecipe implements FixedResultRecipe { return finalResult.getItem(); } - public SimpleRecipeResult result() { + public CustomRecipeResult result() { return this.result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java index df7e682e3..eb0bca8f5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.recipe; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.NotNull; @@ -10,7 +11,7 @@ import java.util.Map; public class CustomSmokingRecipe extends CustomCookingRecipe { public static final Serializer SERIALIZER = new Serializer<>(); - public CustomSmokingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, SimpleRecipeResult result) { + public CustomSmokingRecipe(Key id, CookingRecipeCategory category, String group, Ingredient ingredient, int cookingTime, float experience, CustomRecipeResult result) { super(id, category, group, ingredient, cookingTime, experience, result); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java index b3d517c4b..0476b96d7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.item.recipe; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; @@ -13,7 +14,7 @@ public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { public static final Serializer SERIALIZER = new Serializer<>(); protected final Ingredient ingredient; - public CustomStoneCuttingRecipe(Key id, String group, Ingredient ingredient, SimpleRecipeResult result) { + public CustomStoneCuttingRecipe(Key id, String group, Ingredient ingredient, CustomRecipeResult result) { super(id, group, result); this.ingredient = ingredient; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java index 3bbd1e6f2..757d37533 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java @@ -2,12 +2,15 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; public interface FixedResultRecipe extends Recipe { T result(ItemBuildContext context); - SimpleRecipeResult result(); + CustomRecipeResult result(); + + @Override default T assemble(RecipeInput input, ItemBuildContext context) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/SimpleRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/SimpleRecipeResult.java deleted file mode 100644 index 5ce0ad88f..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/SimpleRecipeResult.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe; - -import net.momirealms.craftengine.core.item.BuildableItem; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Registries; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.ResourceKey; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -@SuppressWarnings("unchecked") -public record SimpleRecipeResult(BuildableItem item, int count, PostProcessor[] postProcessors) { - - public T buildItemStack(ItemBuildContext context) { - return buildItem(context).getItem(); - } - - public Item buildItem(ItemBuildContext context) { - Item builtItem = this.item.buildItem(context, count); - if (this.postProcessors != null) { - for (PostProcessor postProcessor : this.postProcessors) { - builtItem = postProcessor.process(builtItem, context); - } - } - return builtItem; - } - - static { - registerPostProcessorType(Key.of("craftengine", "apply_data"), args -> { - List> modifiers = new ArrayList<>(); - Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); - for (Map.Entry entry : data.entrySet()) { - Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), "craftengine"))) - .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); - } - return new ApplyItemDataProcessor<>(modifiers.toArray(new ItemDataModifier[0])); - }); - } - - public static void registerPostProcessorType(Key id, PostProcessor.Type type) { - ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE) - .register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); - } - - @FunctionalInterface - public interface PostProcessor { - - static PostProcessor fromMap(Map map) { - String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.recipe.result.post_processor.missing_type"); - Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); - PostProcessor.Type processor = (PostProcessor.Type) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE.getValue(key); - if (processor == null) { - throw new LocalizedResourceConfigException("warning.config.recipe.result.post_processor.invalid_type", type); - } - return processor.create(map); - } - - Item process(Item item, ItemBuildContext context); - - interface Type { - - PostProcessor create(Map args); - } - } - - public static class ApplyItemDataProcessor implements PostProcessor { - private final ItemDataModifier[] modifiers; - - public ApplyItemDataProcessor(ItemDataModifier[] modifiers) { - this.modifiers = modifiers; - } - - @Override - public Item process(Item item, ItemBuildContext context) { - for (ItemDataModifier modifier : this.modifiers) { - item.apply(modifier, context); - } - return item; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/ApplyItemDataPostProcessor.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/ApplyItemDataPostProcessor.java new file mode 100644 index 000000000..3ace66275 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/ApplyItemDataPostProcessor.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.item.recipe.result; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; + +public class ApplyItemDataPostProcessor implements PostProcessor { + private final ItemDataModifier[] modifiers; + + public ApplyItemDataPostProcessor(ItemDataModifier[] modifiers) { + this.modifiers = modifiers; + } + + @Override + public Item process(Item item, ItemBuildContext context) { + for (ItemDataModifier modifier : this.modifiers) { + item.apply(modifier, context); + } + return item; + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/CustomRecipeResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/CustomRecipeResult.java new file mode 100644 index 000000000..26e21d102 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/CustomRecipeResult.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.item.recipe.result; + +import net.momirealms.craftengine.core.item.BuildableItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; + +public record CustomRecipeResult(BuildableItem item, int count, PostProcessor[] postProcessors) { + + public T buildItemStack(ItemBuildContext context) { + return buildItem(context).getItem(); + } + + public Item buildItem(ItemBuildContext context) { + Item builtItem = this.item.buildItem(context, this.count); + if (this.postProcessors != null) { + for (PostProcessor postProcessor : this.postProcessors) { + builtItem = postProcessor.process(builtItem, context); + } + } + return builtItem; + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessor.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessor.java new file mode 100644 index 000000000..7e8eb5c2f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessor.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.item.recipe.result; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; + +import java.util.Map; + +public interface PostProcessor { + + Item process(Item item, ItemBuildContext context); + + interface Type { + + PostProcessor create(Map args); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessors.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessors.java new file mode 100644 index 000000000..b091523f5 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/result/PostProcessors.java @@ -0,0 +1,47 @@ +package net.momirealms.craftengine.core.item.recipe.result; + +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@SuppressWarnings("unchecked") +public class PostProcessors { + public static final Key APPLY_DATA = Key.of("craftengine:apply_data"); + + static { + registerPostProcessorType(APPLY_DATA, args -> { + List> modifiers = new ArrayList<>(); + Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); + for (Map.Entry entry : data.entrySet()) { + Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), Key.DEFAULT_NAMESPACE))) + .ifPresent(factory -> modifiers.add(factory.create(entry.getValue()))); + } + return new ApplyItemDataPostProcessor<>(modifiers.toArray(new ItemDataModifier[0])); + }); + } + + public static PostProcessor fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.recipe.result.post_processor.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + PostProcessor.Type processor = (PostProcessor.Type) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE.getValue(key); + if (processor == null) { + throw new LocalizedResourceConfigException("warning.config.recipe.result.post_processor.invalid_type", type); + } + return processor.create(map); + } + + public static void registerPostProcessorType(Key id, PostProcessor.Type type) { + ((WritableRegistry>) BuiltInRegistries.RECIPE_POST_PROCESSOR_TYPE) + .register(ResourceKey.create(Registries.RECIPE_POST_PROCESSOR_TYPE.location(), id), type); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 061c5d4fc..482b2e1d5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -10,10 +10,10 @@ import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeSerializer; -import net.momirealms.craftengine.core.item.recipe.SimpleRecipeResult; import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; +import net.momirealms.craftengine.core.item.recipe.result.PostProcessor; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; @@ -78,7 +78,7 @@ public class BuiltInRegistries { public static final Registry SLOT_DISPLAY_TYPE = createConstantBoundRegistry(Registries.SLOT_DISPLAY_TYPE); public static final Registry RECIPE_DISPLAY_TYPE = createConstantBoundRegistry(Registries.RECIPE_DISPLAY_TYPE); public static final Registry LEGACY_RECIPE_TYPE = createConstantBoundRegistry(Registries.LEGACY_RECIPE_TYPE); - public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); + public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); private static Registry createConstantBoundRegistry(ResourceKey> key) { return new ConstantBoundRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 291233df3..78e68ec0e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -10,10 +10,10 @@ import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeSerializer; -import net.momirealms.craftengine.core.item.recipe.SimpleRecipeResult; import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; +import net.momirealms.craftengine.core.item.recipe.result.PostProcessor; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; @@ -80,5 +80,5 @@ public class Registries { public static final ResourceKey> SLOT_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("slot_display_type")); public static final ResourceKey> RECIPE_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_display_type")); public static final ResourceKey> LEGACY_RECIPE_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("legacy_recipe_type")); - public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); + public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); }