From 45859fd661b917cc88994a68bc3f840fbf461718 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 15 Mar 2025 22:50:57 +0800 Subject: [PATCH 1/8] fix trim --- .../resources/default/configuration/items.yml | 117 ++++++++++++++++-- .../models/block/custom/fairy_flower_1.json | 1 - .../minecraft/models/item/custom/bench.json | 4 +- .../models/item/custom/table_lamp.json | 4 +- .../models/item/custom/wooden_chair.json | 111 ++++++++--------- .../bukkit/item/BukkitItemManager.java | 51 +++++--- .../select/TrimMaterialSelectProperty.java | 12 +- 7 files changed, 211 insertions(+), 89 deletions(-) diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/items.yml b/bukkit-loader/src/main/resources/resources/default/configuration/items.yml index b5db59a86..54c02a507 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/items.yml @@ -153,19 +153,122 @@ templates: data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz - model: - type: minecraft:model - path: "minecraft:item/custom/topaz_{part}" - generation: - parent: "minecraft:item/generated" - textures: - "layer0": "minecraft:item/custom/topaz_{part}" settings: equippable: slot: "{slot}" asset-id: topaz humanoid: "minecraft:topaz" humanoid-leggings: "minecraft:topaz" + model: + type: minecraft:select + property: minecraft:trim_material + fallback: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + cases: + - when: minecraft:quartz + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_quartz_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_quartz" + - when: minecraft:iron + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_iron_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_iron" + - when: minecraft:netherite + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_netherite_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_netherite" + - when: minecraft:redstone + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_redstone_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_redstone" + - when: minecraft:copper + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_copper_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_copper" + - when: minecraft:gold + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_gold_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_gold" + - when: minecraft:emerald + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_emerald_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_emerald" + - when: minecraft:diamond + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_diamond_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_diamond" + - when: minecraft:lapis + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_lapis_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_lapis" + - when: minecraft:amethyst + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_amethyst_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_amethyst" + - when: minecraft:resin + model: + type: minecraft:model + path: "minecraft:item/custom/topaz_{part}_resin_trim" + generation: + parent: "minecraft:item/generated" + textures: + "layer0": "minecraft:item/custom/topaz_{part}" + "layer1": "minecraft:trims/items/{part}_trim_resin" recipes#11: default:topaz_shovel: diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json index fd7176e69..44c9adbde 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json @@ -1,5 +1,4 @@ { - "credit": "XiaoMoMi", "textures": { "0": "block/custom/fairy_flower_1", "particle": "block/custom/fairy_flower_1" diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json index 7d88139de..563e589db 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json @@ -1,9 +1,7 @@ { - "credit": "MadewithBlockbench", "texture_size": [64, 64], "textures": { - "0": "item/custom/bench", - "particle": "item/custom/bench" + "0": "item/custom/bench" }, "elements": [ { diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json index 31bb35cfa..bb2e8fdf6 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json @@ -1,9 +1,7 @@ { - "credit": "Made with Blockbench", "texture_size": [32, 32], "textures": { - "0": "item/custom/table_lamp", - "particle": "item/custom/table_lamp" + "0": "item/custom/table_lamp" }, "elements": [ { diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json index dd4fac5a3..ca279830c 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json @@ -1,8 +1,7 @@ { - "credit": "Made with Blockbench", "texture_size": [32, 32], "textures": { - "1": "item/custom/wooden_chair" + "0": "item/custom/wooden_chair" }, "elements": [ { @@ -10,12 +9,12 @@ "to": [5.25, 7.25, 5.25], "rotation": {"angle": 0, "axis": "y", "origin": [4.5, 4, 4.5]}, "faces": { - "north": {"uv": [15.5, 0.5, 16, 4], "texture": "#1"}, - "east": {"uv": [15, 0.5, 15.5, 4], "texture": "#1"}, - "south": {"uv": [15, 0.5, 15.5, 4], "texture": "#1"}, - "west": {"uv": [15.5, 0.5, 16, 4], "texture": "#1"}, - "up": {"uv": [16, 0.5, 15.5, 0], "texture": "#1"}, - "down": {"uv": [15.5, 0, 15, 0.5], "texture": "#1"} + "north": {"uv": [15.5, 0.5, 16, 4], "texture": "#0"}, + "east": {"uv": [15, 0.5, 15.5, 4], "texture": "#0"}, + "south": {"uv": [15, 0.5, 15.5, 4], "texture": "#0"}, + "west": {"uv": [15.5, 0.5, 16, 4], "texture": "#0"}, + "up": {"uv": [16, 0.5, 15.5, 0], "texture": "#0"}, + "down": {"uv": [15.5, 0, 15, 0.5], "texture": "#0"} } }, { @@ -23,12 +22,12 @@ "to": [12.25, 7.25, 5.25], "rotation": {"angle": 0, "axis": "y", "origin": [11.5, 3.5, 4.5]}, "faces": { - "north": {"uv": [16, 0.5, 15.5, 4], "texture": "#1"}, - "east": {"uv": [16, 0.5, 15.5, 4], "texture": "#1"}, - "south": {"uv": [15.5, 0.5, 15, 4], "texture": "#1"}, - "west": {"uv": [15.5, 0.5, 15, 4], "texture": "#1"}, - "up": {"uv": [15.5, 0.5, 16, 0], "texture": "#1"}, - "down": {"uv": [15, 0, 15.5, 0.5], "texture": "#1"} + "north": {"uv": [16, 0.5, 15.5, 4], "texture": "#0"}, + "east": {"uv": [16, 0.5, 15.5, 4], "texture": "#0"}, + "south": {"uv": [15.5, 0.5, 15, 4], "texture": "#0"}, + "west": {"uv": [15.5, 0.5, 15, 4], "texture": "#0"}, + "up": {"uv": [15.5, 0.5, 16, 0], "texture": "#0"}, + "down": {"uv": [15, 0, 15.5, 0.5], "texture": "#0"} } }, { @@ -36,12 +35,12 @@ "to": [12.25, 7.25, 12.25], "rotation": {"angle": 0, "axis": "y", "origin": [11.5, 4, 11.5]}, "faces": { - "north": {"uv": [15, 0.5, 15.5, 4], "texture": "#1"}, - "east": {"uv": [15.5, 0.5, 16, 4], "texture": "#1"}, - "south": {"uv": [15.5, 0.5, 16, 4], "texture": "#1"}, - "west": {"uv": [15, 0.5, 15.5, 4], "texture": "#1"}, - "up": {"uv": [15.5, 0, 16, 0.5], "texture": "#1"}, - "down": {"uv": [15, 0.5, 15.5, 0], "texture": "#1"} + "north": {"uv": [15, 0.5, 15.5, 4], "texture": "#0"}, + "east": {"uv": [15.5, 0.5, 16, 4], "texture": "#0"}, + "south": {"uv": [15.5, 0.5, 16, 4], "texture": "#0"}, + "west": {"uv": [15, 0.5, 15.5, 4], "texture": "#0"}, + "up": {"uv": [15.5, 0, 16, 0.5], "texture": "#0"}, + "down": {"uv": [15, 0.5, 15.5, 0], "texture": "#0"} } }, { @@ -49,12 +48,12 @@ "to": [5.25, 7.25, 12.25], "rotation": {"angle": 0, "axis": "y", "origin": [4.5, 4, 11.5]}, "faces": { - "north": {"uv": [15.5, 0.5, 15, 4], "texture": "#1"}, - "east": {"uv": [15.5, 0.5, 15, 4], "texture": "#1"}, - "south": {"uv": [16, 0.5, 15.5, 4], "texture": "#1"}, - "west": {"uv": [16, 0.5, 15.5, 4], "texture": "#1"}, - "up": {"uv": [16, 0, 15.5, 0.5], "texture": "#1"}, - "down": {"uv": [15.5, 0.5, 15, 0], "texture": "#1"} + "north": {"uv": [15.5, 0.5, 15, 4], "texture": "#0"}, + "east": {"uv": [15.5, 0.5, 15, 4], "texture": "#0"}, + "south": {"uv": [16, 0.5, 15.5, 4], "texture": "#0"}, + "west": {"uv": [16, 0.5, 15.5, 4], "texture": "#0"}, + "up": {"uv": [16, 0, 15.5, 0.5], "texture": "#0"}, + "down": {"uv": [15.5, 0.5, 15, 0], "texture": "#0"} } }, { @@ -62,12 +61,12 @@ "to": [12, 17, 12], "rotation": {"angle": 0, "axis": "y", "origin": [4, 9, 14]}, "faces": { - "north": {"uv": [4, 5, 0, 9], "texture": "#1"}, - "east": {"uv": [0, 0, 0, 4], "texture": "#1"}, - "south": {"uv": [0, 5, 4, 9], "texture": "#1"}, - "west": {"uv": [0, 0, 0, 4], "texture": "#1"}, - "up": {"uv": [4, 0, 0, 0], "texture": "#1"}, - "down": {"uv": [4, 0, 0, 0], "texture": "#1"} + "north": {"uv": [4, 5, 0, 9], "texture": "#0"}, + "east": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "south": {"uv": [0, 5, 4, 9], "texture": "#0"}, + "west": {"uv": [0, 0, 0, 4], "texture": "#0"}, + "up": {"uv": [4, 0, 0, 0], "texture": "#0"}, + "down": {"uv": [4, 0, 0, 0], "texture": "#0"} } }, { @@ -75,12 +74,12 @@ "to": [12, 18.5, 12.5], "rotation": {"angle": 0, "axis": "y", "origin": [4, 17, 14]}, "faces": { - "north": {"uv": [8, 5, 4, 6], "texture": "#1"}, - "east": {"uv": [8, 5, 8.5, 6], "texture": "#1"}, - "south": {"uv": [4, 5, 8, 6], "texture": "#1"}, - "west": {"uv": [8, 5, 8.5, 6], "texture": "#1"}, - "up": {"uv": [8, 7, 4, 6.5], "texture": "#1"}, - "down": {"uv": [8, 6, 4, 6.5], "texture": "#1"} + "north": {"uv": [8, 5, 4, 6], "texture": "#0"}, + "east": {"uv": [8, 5, 8.5, 6], "texture": "#0"}, + "south": {"uv": [4, 5, 8, 6], "texture": "#0"}, + "west": {"uv": [8, 5, 8.5, 6], "texture": "#0"}, + "up": {"uv": [8, 7, 4, 6.5], "texture": "#0"}, + "down": {"uv": [8, 6, 4, 6.5], "texture": "#0"} } }, { @@ -88,12 +87,12 @@ "to": [4, 19, 13], "rotation": {"angle": 0, "axis": "y", "origin": [3, 9, 13]}, "faces": { - "north": {"uv": [0.5, 11, 1, 16], "texture": "#1"}, - "east": {"uv": [2, 11, 3, 16], "texture": "#1"}, - "south": {"uv": [0, 11, 0.5, 16], "texture": "#1"}, - "west": {"uv": [1, 11, 2, 16], "texture": "#1"}, - "up": {"uv": [2, 11, 1, 10.5], "rotation": 90, "texture": "#1"}, - "down": {"uv": [2, 11, 3, 10.5], "rotation": 90, "texture": "#1"} + "north": {"uv": [0.5, 11, 1, 16], "texture": "#0"}, + "east": {"uv": [2, 11, 3, 16], "texture": "#0"}, + "south": {"uv": [0, 11, 0.5, 16], "texture": "#0"}, + "west": {"uv": [1, 11, 2, 16], "texture": "#0"}, + "up": {"uv": [2, 11, 1, 10.5], "rotation": 90, "texture": "#0"}, + "down": {"uv": [2, 11, 3, 10.5], "rotation": 90, "texture": "#0"} } }, { @@ -101,12 +100,12 @@ "to": [13, 19, 13], "rotation": {"angle": 0, "axis": "y", "origin": [13, 9, 13]}, "faces": { - "north": {"uv": [1, 11, 0.5, 16], "texture": "#1"}, - "east": {"uv": [2, 11, 1, 16], "texture": "#1"}, - "south": {"uv": [0.5, 11, 0, 16], "texture": "#1"}, - "west": {"uv": [3, 11, 2, 16], "texture": "#1"}, - "up": {"uv": [2, 10.5, 1, 11], "rotation": 90, "texture": "#1"}, - "down": {"uv": [2, 10.5, 3, 11], "rotation": 90, "texture": "#1"} + "north": {"uv": [1, 11, 0.5, 16], "texture": "#0"}, + "east": {"uv": [2, 11, 1, 16], "texture": "#0"}, + "south": {"uv": [0.5, 11, 0, 16], "texture": "#0"}, + "west": {"uv": [3, 11, 2, 16], "texture": "#0"}, + "up": {"uv": [2, 10.5, 1, 11], "rotation": 90, "texture": "#0"}, + "down": {"uv": [2, 10.5, 3, 11], "rotation": 90, "texture": "#0"} } }, { @@ -114,12 +113,12 @@ "to": [13, 9, 13], "rotation": {"angle": 0, "axis": "y", "origin": [3, 7, 5]}, "faces": { - "north": {"uv": [10, 2, 15, 3], "texture": "#1"}, - "east": {"uv": [10, 0, 15, 1], "texture": "#1"}, - "south": {"uv": [10, 1, 15, 2], "texture": "#1"}, - "west": {"uv": [15, 0, 10, 1], "texture": "#1"}, - "up": {"uv": [5, 5, 0, 0], "texture": "#1"}, - "down": {"uv": [10, 0, 5, 5], "texture": "#1"} + "north": {"uv": [10, 2, 15, 3], "texture": "#0"}, + "east": {"uv": [10, 0, 15, 1], "texture": "#0"}, + "south": {"uv": [10, 1, 15, 2], "texture": "#0"}, + "west": {"uv": [15, 0, 10, 1], "texture": "#0"}, + "up": {"uv": [5, 5, 0, 0], "texture": "#0"}, + "down": {"uv": [10, 0, 5, 5], "texture": "#0"} } } ], 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 84fa5ecc2..9aaf2eb05 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 @@ -21,6 +21,8 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.pack.model.*; 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.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -454,13 +456,19 @@ public class BukkitItemManager extends AbstractItemManager { for (Map.Entry>, ItemModel> entry : model.whenMap().entrySet()) { List cases = entry.getKey().fallbackOrMapPrimary(List::of); for (String caseValue : cases) { + Number legacyValue = predicate.toLegacyValue(caseValue); + if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { + if (legacyValue.floatValue() > 1f) { + continue; + } + } Map merged = mergePredicates( parentPredicates, predicateId, - predicate.toLegacyValue(caseValue) + legacyValue ); // Additional check for crossbow - if (materialId.equals(ItemKeys.CROSSBOW)) { + if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { merged = mergePredicates( merged, "charged", @@ -477,19 +485,32 @@ public class BukkitItemManager extends AbstractItemManager { } } // Additional check for crossbow - if (model.fallBack() != null && materialId.equals(ItemKeys.CROSSBOW)) { - Map merged = mergePredicates( - parentPredicates, - "charged", - 0 - ); - processModelRecursively( - model.fallBack(), - merged, - resultList, - materialId, - customModelData - ); + if (model.fallBack() != null) { + if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { + processModelRecursively( + model.fallBack(), + mergePredicates( + parentPredicates, + "charged", + 0 + ), + resultList, + materialId, + customModelData + ); + } else if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { + processModelRecursively( + model.fallBack(), + mergePredicates( + parentPredicates, + "trim_type", + 0f + ), + resultList, + materialId, + customModelData + ); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java index ce658ffff..ea17d87f9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java @@ -22,7 +22,7 @@ public class TrimMaterialSelectProperty implements SelectProperty, LegacyModelPr LEGACY_TRIM_DATA.put("minecraft:lapis", 0.9f); LEGACY_TRIM_DATA.put("minecraft:amethyst", 1.0f); // INVALID - LEGACY_TRIM_DATA.put("minecraft:resin", 0F); + LEGACY_TRIM_DATA.put("minecraft:resin", 1.1F); } @Override @@ -37,9 +37,8 @@ public class TrimMaterialSelectProperty implements SelectProperty, LegacyModelPr @Override public String legacyPredicateId(Key material) { - String s = material.toString(); - if (s.contains("helmet") || s.contains("chestplate") || s.contains("leggings") || s.contains("boots")) { - return "trim"; + if (isArmor(material)) { + return "trim_type"; } return null; } @@ -53,6 +52,11 @@ public class TrimMaterialSelectProperty implements SelectProperty, LegacyModelPr return f; } + public boolean isArmor(Key material) { + String s = material.toString(); + return s.contains("helmet") || s.contains("chestplate") || s.contains("leggings") || s.contains("boots"); + } + public static class Factory implements SelectPropertyFactory { @Override From 6cc7320edd6132aec2ff1a6038aa28ee05b1bee8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 15 Mar 2025 23:44:54 +0800 Subject: [PATCH 2/8] added repair recipe --- .../item/recipe/RecipeEventListener.java | 75 ++++++++++++++++++- .../craftengine/bukkit/util/Reflections.java | 26 +++++++ 2 files changed, 98 insertions(+), 3 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 2a6175da4..e9faf23ea 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 @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.Pair; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.context.ContextHolder; import org.bukkit.Material; @@ -438,18 +439,86 @@ public class RecipeEventListener implements Listener { } } + // only handle repair items for the moment @EventHandler(ignoreCancelled = true) public void onSpecialRecipe(PrepareItemCraftEvent event) { if (!ConfigManager.enableRecipeSystem()) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); if (recipe == null) return; - if (!(recipe instanceof ComplexRecipe)) + if (!(recipe instanceof ComplexRecipe complexRecipe)) return; CraftingInventory inventory = event.getInventory(); - if (ItemUtils.hasCustomItem(inventory.getMatrix())) { - inventory.setResult(null); + boolean hasCustomItem = ItemUtils.hasCustomItem(inventory.getMatrix()); + if (!hasCustomItem) { + return; } + + if (!Reflections.clazz$CraftComplexRecipe.isInstance(complexRecipe)) { + inventory.setResult(null); + return; + } + + try { + Object mcRecipe = Reflections.field$CraftComplexRecipe$recipe.get(complexRecipe); + if (!Reflections.clazz$RepairItemRecipe.isInstance(mcRecipe)) { + inventory.setResult(null); + return; + } + + // 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().get() + right.maxDamage().get(); + // should be impossible, but take care + if (totalDamage >= totalMaxDamage) { + inventory.setResult(null); + return; + } + + Player player; + try { + player = (Player) Reflections.method$InventoryView$getPlayer.invoke(event.getView()); + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to get inventory viewer", e); + return; + } + + Item newItem = plugin.itemManager().getCustomItem(left.id()).get().buildItem(ItemBuildContext.of(plugin.adapt(player), ContextHolder.EMPTY)); + int remainingDurability = totalMaxDamage - totalDamage; + int newItemDamage = Math.max(0, newItem.maxDamage().get() - remainingDurability); + newItem.damage(newItemDamage); + inventory.setResult(newItem.load()); + } catch (Exception e) { + this.plugin.logger().warn("Failed to handle minecraft custom recipe", e); + } + } + + private Pair getTheOnlyTwoItem(ItemStack[] matrix) { + ItemStack first = null; + ItemStack second = null; + for (ItemStack itemStack : matrix) { + if (itemStack == null) continue; + if (first == null) { + first = itemStack; + } else if (second == null) { + second = itemStack; + } + } + return new Pair<>(first, second); } @EventHandler(ignoreCancelled = true) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 1afda911d..b4787d9e5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -4860,4 +4860,30 @@ public class Reflections { clazz$FluidState, clazz$Fluid ) ); + + public static final Class clazz$CraftComplexRecipe = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleCBClass("inventory.CraftComplexRecipe") + ) + ); + + public static final Class clazz$CustomRecipe = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.item.crafting.CustomRecipe"), + BukkitReflectionUtils.assembleMCClass("world.item.crafting.IRecipeComplex") + ) + ); + + public static final Class clazz$RepairItemRecipe = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.item.crafting.RepairItemRecipe"), + BukkitReflectionUtils.assembleMCClass("world.item.crafting.RecipeRepair") + ) + ); + + public static final Field field$CraftComplexRecipe$recipe = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$CraftComplexRecipe, clazz$CustomRecipe, 0 + ) + ); } From 70a978dc7952bd4de7aaa1ce88acbb5c1e8270bf Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 15 Mar 2025 23:47:37 +0800 Subject: [PATCH 3/8] added repairable --- .../bukkit/item/recipe/RecipeEventListener.java | 15 ++++++++++++++- .../craftengine/core/item/ItemSettings.java | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) 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 e9faf23ea..bdd1a5d52 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 @@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.Reflections; +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.ItemManager; @@ -497,7 +498,19 @@ public class RecipeEventListener implements Listener { return; } - Item newItem = plugin.itemManager().getCustomItem(left.id()).get().buildItem(ItemBuildContext.of(plugin.adapt(player), ContextHolder.EMPTY)); + Optional> customItemOptional = plugin.itemManager().getCustomItem(left.id()); + if (!customItemOptional.isPresent()) { + 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), ContextHolder.EMPTY)); int remainingDurability = totalMaxDamage - totalDamage; int newItemDamage = Math.max(0, newItem.maxDamage().get() - remainingDurability); newItem.damage(newItemDamage); 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 c45c1d7aa..c8bf5c432 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 @@ -16,6 +16,7 @@ public class ItemSettings { Set tags = Set.of(); @Nullable EquipmentGeneration equipment; + boolean canRepair = true; private ItemSettings() {} @@ -39,6 +40,7 @@ public class ItemSettings { newSettings.fuelTime = settings.fuelTime; newSettings.tags = settings.tags; newSettings.equipment = settings.equipment; + newSettings.canRepair = settings.canRepair; return newSettings; } @@ -54,6 +56,10 @@ public class ItemSettings { return settings; } + public boolean canRepair() { + return canRepair; + } + public int fuelTime() { return fuelTime; } @@ -67,6 +73,11 @@ public class ItemSettings { return equipment; } + public ItemSettings canRepair(boolean canRepair) { + this.canRepair = canRepair; + return this; + } + public ItemSettings fuelTime(int fuelTime) { this.fuelTime = fuelTime; return this; @@ -98,6 +109,10 @@ public class ItemSettings { private static final Map FACTORIES = new HashMap<>(); static { + registerFactory("repairable", (value -> { + boolean bool = (boolean) value; + return settings -> settings.canRepair(bool); + })); registerFactory("fuel-time", (value -> { int intValue = MiscUtils.getAsInt(value); return settings -> settings.fuelTime(intValue); From 1eef1794b6e8bbf020e6ee9dc03ae44e8ba05429 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 16 Mar 2025 02:25:42 +0800 Subject: [PATCH 4/8] fix i18n loading sequence --- .../resources/default/configuration/items.yml | 26 ++++ .../resources/default/configuration/ores.yml | 5 + .../bukkit/util/LegacyInventoryUtils.java | 6 + .../item/recipe/RecipeEventListener.java | 138 +++++++++++++++++- .../core/item/AnvilRepairItem.java | 6 + .../craftengine/core/item/CustomItem.java | 4 + .../craftengine/core/item/ItemSettings.java | 24 ++- .../core/pack/LoadingSequence.java | 16 +- 8 files changed, 209 insertions(+), 16 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/AnvilRepairItem.java diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/items.yml b/bukkit-loader/src/main/resources/resources/default/configuration/items.yml index 54c02a507..ba4034232 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/items.yml @@ -2,6 +2,9 @@ items: default:topaz_rod: material: fishing_rod custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -15,6 +18,9 @@ items: default:topaz_bow: material: bow custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -32,6 +38,9 @@ items: default:topaz_crossbow: material: crossbow custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -53,6 +62,9 @@ items: default:topaz_pickaxe: material: golden_pickaxe custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -68,6 +80,9 @@ items: default:topaz_axe: material: golden_axe custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -83,6 +98,9 @@ items: default:topaz_hoe: material: golden_hoe custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -98,6 +116,9 @@ items: default:topaz_shovel: material: golden_shovel custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -113,6 +134,9 @@ items: default:topaz_sword: material: golden_sword custom-model-data: 1000 + settings: + tags: + - "topaz_tools" data: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz @@ -154,6 +178,8 @@ templates: display-name: "<#FF8C00>" tooltip-style: minecraft:topaz settings: + tags: + - "topaz_tools" equippable: slot: "{slot}" asset-id: topaz diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml b/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml index 19fd10f4c..f1bdfb981 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml @@ -28,6 +28,11 @@ items: default:topaz: material: paper custom-model-data: 1012 + settings: + anvil-repair-item: + - target: + - "#topaz_tools" + percent: 0.25 data: display-name: "<#FF8C00>" model: diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java index 7abee98f0..ddbad77d5 100644 --- a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.util; import org.bukkit.entity.Player; +import org.bukkit.inventory.AnvilInventory; import org.bukkit.inventory.Inventory; public class LegacyInventoryUtils { @@ -8,4 +9,9 @@ public class LegacyInventoryUtils { public static Inventory getTopInventory(Player player) { return player.getOpenInventory().getTopInventory(); } + + public static void setRepairCost(AnvilInventory anvilInventory, int repairCost, int amount) { + anvilInventory.setRepairCost(repairCost); + anvilInventory.setRepairCostAmount(amount); + } } 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 bdd1a5d52..e6106e8d3 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 @@ -6,17 +6,16 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.bukkit.util.Reflections; -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.ItemManager; +import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.recipe.CustomCampfireRecipe; import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -36,11 +35,13 @@ import org.bukkit.event.block.*; import org.bukkit.event.inventory.*; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.*; +import org.bukkit.inventory.view.AnvilView; import java.util.ArrayList; import java.util.List; import java.util.Optional; +@SuppressWarnings("DuplicatedCode") public class RecipeEventListener implements Listener { private static final OptimizedIDItem EMPTY = new OptimizedIDItem<>(null, null); private final ItemManager itemManager; @@ -366,6 +367,7 @@ public class RecipeEventListener implements Listener { } // for 1.21.2+ + @SuppressWarnings("UnstableApiUsage") @EventHandler(ignoreCancelled = true) public void onCampfireCook(CampfireStartEvent event) { if (!ConfigManager.enableRecipeSystem()) return; @@ -404,6 +406,8 @@ public class RecipeEventListener implements Listener { 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); @@ -432,7 +436,7 @@ public class RecipeEventListener implements Listener { // Paper only @EventHandler public void onPrepareResult(PrepareResultEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; +// if (!ConfigManager.enableRecipeSystem()) return; if (event.getInventory() instanceof CartographyInventory cartographyInventory) { if (ItemUtils.hasCustomItem(cartographyInventory.getStorageContents())) { event.setResult(new ItemStack(Material.AIR)); @@ -440,10 +444,130 @@ public class RecipeEventListener implements Listener { } } + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) + public void onAnvilCombineItems(PrepareAnvilEvent event) { + AnvilInventory inventory = event.getInventory(); + ItemStack first = inventory.getFirstItem(); + ItemStack second = inventory.getSecondItem(); + if (first == null || second == null) return; + Item wrappedFirst = BukkitItemManager.instance().wrap(first); + boolean firstCustom = wrappedFirst.isCustomItem(); + Item wrappedSecond = BukkitItemManager.instance().wrap(second); + boolean secondCustom = wrappedSecond.isCustomItem(); + // both are vanilla items + if (!firstCustom && !secondCustom) { + return; + } + + // one of them is vanilla item + if (!firstCustom || !secondCustom) { + // block "vanilla + custom" recipes + if (wrappedFirst.vanillaId().equals(wrappedSecond.vanillaId())) { + event.setResult(null); + } + return; + } + + // both of them are custom items + // if the second is an enchanted book, then apply it + if (wrappedSecond.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { + return; + } + + // not the same item + if (!wrappedFirst.customId().equals(wrappedSecond.customId())) { + event.setResult(null); + return; + } + + // can not repair + wrappedFirst.getCustomItem().ifPresent(it -> { + if (!it.settings().canRepair()) { + event.setResult(null); + } + }); + } + + @SuppressWarnings("UnstableApiUsage") + @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) + public void onAnvilRepairItems(PrepareAnvilEvent event) { + AnvilInventory inventory = event.getInventory(); + ItemStack first = inventory.getFirstItem(); + ItemStack second = inventory.getSecondItem(); + if (first == null || second == null) return; + + Item wrappedSecond = BukkitItemManager.instance().wrap(second); + // if the second slot is not a custom item, ignore it + Optional> customItemOptional = plugin.itemManager().getCustomItem(wrappedSecond.id()); + if (customItemOptional.isEmpty()) { + return; + } + + CustomItem customItem = customItemOptional.get(); + List repairItems = customItem.settings().repairItems(); + // if the second slot is not a repair item, ignore it + if (repairItems.isEmpty()) { + return; + } + + Item wrappedFirst = BukkitItemManager.instance().wrap(first); + int damage = wrappedFirst.damage().orElse(0); + int maxDamage = wrappedFirst.maxDamage().orElse(0); + // not a repairable item + if (maxDamage == 0 || damage == 0) return; + + Key firstId = wrappedFirst.id(); + Optional> optionalCustomTool = wrappedFirst.getCustomItem(); + // can not repair + if (optionalCustomTool.isPresent() && !optionalCustomTool.get().settings().canRepair()) { + return; + } + + AnvilRepairItem repairItem = null; + for (AnvilRepairItem item : repairItems) { + for (String target : item.targets()) { + if (target.charAt(0) == '#') { + Key tag = Key.of(target.substring(1)); + if (optionalCustomTool.isPresent() && optionalCustomTool.get().is(tag)) { + repairItem = item; + break; + } + if (wrappedFirst.is(tag)) { + repairItem = item; + break; + } + } else if (target.equals(firstId.toString())) { + repairItem = item; + break; + } + } + } + + // no repair item matching + if (repairItem == null) { + return; + } + + int realDurabilityPerItem = (int) (repairItem.amount() + repairItem.percent() * maxDamage); + int consumeMaxAmount = damage / realDurabilityPerItem + 1; + int actualConsumedAmount = Math.min(consumeMaxAmount, wrappedSecond.count()); + int actualRepairAmount = actualConsumedAmount * realDurabilityPerItem; + int damageAfter = Math.max(damage - actualRepairAmount, 0); + wrappedFirst.damage(damageAfter); + event.setResult(wrappedFirst.loadCopy()); + if (VersionHelper.isVersionNewerThan1_21()) { + AnvilView anvilView = event.getView(); + anvilView.setRepairCost(10); + anvilView.setRepairItemCountCost(actualConsumedAmount); + } else { + LegacyInventoryUtils.setRepairCost(inventory, 10, actualRepairAmount); + } + } + // only handle repair items for the moment @EventHandler(ignoreCancelled = true) public void onSpecialRecipe(PrepareItemCraftEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; +// if (!ConfigManager.enableRecipeSystem()) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); if (recipe == null) return; @@ -499,7 +623,7 @@ public class RecipeEventListener implements Listener { } Optional> customItemOptional = plugin.itemManager().getCustomItem(left.id()); - if (!customItemOptional.isPresent()) { + if (customItemOptional.isEmpty()) { inventory.setResult(null); return; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AnvilRepairItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AnvilRepairItem.java new file mode 100644 index 000000000..8ea18261d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AnvilRepairItem.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.item; + +import java.util.List; + +public record AnvilRepairItem(List targets, int amount, double percent) { +} 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 e3dabdc37..916f7a510 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 @@ -19,6 +19,10 @@ public interface CustomItem extends BuildableItem { ItemSettings settings(); + default boolean is(Key tag) { + return settings().tags().contains(tag); + } + default Item buildItem(Player player) { return buildItem(new ItemBuildContext(player, ContextHolder.EMPTY)); } 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 c8bf5c432..c56197dc1 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 @@ -17,13 +17,14 @@ public class ItemSettings { @Nullable EquipmentGeneration equipment; boolean canRepair = true; + List anvilRepairItems = List.of(); private ItemSettings() {} public List> modifiers() { ArrayList> modifiers = new ArrayList<>(); if (VersionHelper.isVersionNewerThan1_21_2() && this.equipment != null && this.equipment.modernData() != null) modifiers.add(new EquippableModifier<>(this.equipment.modernData())); - + // TODO 1.20 return modifiers; } @@ -41,6 +42,7 @@ public class ItemSettings { newSettings.tags = settings.tags; newSettings.equipment = settings.equipment; newSettings.canRepair = settings.canRepair; + newSettings.anvilRepairItems = settings.anvilRepairItems; return newSettings; } @@ -68,11 +70,20 @@ public class ItemSettings { return tags; } + public List repairItems() { + return anvilRepairItems; + } + @Nullable public EquipmentGeneration equipment() { return equipment; } + public ItemSettings repairItems(List items) { + this.anvilRepairItems = items; + return this; + } + public ItemSettings canRepair(boolean canRepair) { this.canRepair = canRepair; return this; @@ -113,6 +124,17 @@ public class ItemSettings { boolean bool = (boolean) value; return settings -> settings.canRepair(bool); })); + registerFactory("anvil-repair-item", (value -> { + @SuppressWarnings("unchecked") + List> materials = (List>) value; + List anvilRepairItemList = new ArrayList<>(); + for (Map material : materials) { + int amount = MiscUtils.getAsInt(material.getOrDefault("amount", 0)); + double percent = MiscUtils.getAsDouble(material.getOrDefault("percent", 0)); + anvilRepairItemList.add(new AnvilRepairItem(MiscUtils.getAsStringList(material.get("target")), amount, percent)); + } + return settings -> settings.repairItems(anvilRepairItemList); + })); registerFactory("fuel-time", (value -> { int intValue = MiscUtils.getAsInt(value); return settings -> settings.fuelTime(intValue); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java index fc810fa83..fbb6cf742 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java @@ -2,14 +2,14 @@ package net.momirealms.craftengine.core.pack; public class LoadingSequence { public static final int TEMPLATE = 0; - public static final int BLOCK = 10; - public static final int ITEM = 20; - public static final int FURNITURE = 30; - public static final int FONT = 40; - public static final int RECIPE = 50; - public static final int CATEGORY = 60; - public static final int TRANSLATION = 70; - public static final int LANG = 80; + public static final int LANG = 10; + public static final int TRANSLATION = 20; + public static final int BLOCK = 30; + public static final int ITEM = 40; + public static final int FURNITURE = 50; + public static final int FONT = 60; + public static final int RECIPE = 70; + public static final int CATEGORY = 80; public static final int SOUND = 90; public static final int JUKEBOX_SONG = 100; } From 2c0a073f189724b765a6f5d80a7c791a1cbe269d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 16 Mar 2025 04:11:22 +0800 Subject: [PATCH 5/8] anvil repair system --- .../default/configuration/blocks.yml | 2 +- .../default/configuration/fairy_flower.yml | 2 +- .../default/configuration/furniture.yml | 6 +- .../resources/default/configuration/items.yml | 18 ++-- .../resources/default/configuration/ores.yml | 6 +- .../default/configuration/palm_tree.yml | 14 +-- .../resources/internal/configuration/gui.yml | 10 +- .../bukkit/util/LegacyInventoryUtils.java | 16 +++ .../item/factory/ComponentItemFactory.java | 19 +++- .../item/factory/UniversalItemFactory.java | 19 +++- .../item/recipe/RecipeEventListener.java | 100 +++++++++++++++--- .../bukkit/util/ComponentUtils.java | 4 + .../craftengine/bukkit/util/Reflections.java | 6 ++ .../craftengine/core/item/AbstractItem.java | 19 +++- .../core/item/AbstractItemManager.java | 12 +-- .../craftengine/core/item/ComponentKeys.java | 1 + .../craftengine/core/item/Item.java | 12 ++- .../craftengine/core/item/ItemFactory.java | 8 +- .../item/modifier/DisplayNameModifier.java | 2 +- .../gui/category/ItemBrowserManagerImpl.java | 4 +- .../core/util/AdventureHelper.java | 2 +- 21 files changed, 212 insertions(+), 70 deletions(-) diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit-loader/src/main/resources/resources/default/configuration/blocks.yml index c807b25e2..49e05743b 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/blocks.yml @@ -3,7 +3,7 @@ items: material: paper custom-model-data: 3001 data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/chinese_lantern" diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/fairy_flower.yml b/bukkit-loader/src/main/resources/resources/default/configuration/fairy_flower.yml index c1484240c..190e39b8d 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/fairy_flower.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/fairy_flower.yml @@ -3,7 +3,7 @@ items: material: paper custom-model-data: 3000 data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/fairy_flower" diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/furniture.yml b/bukkit-loader/src/main/resources/resources/default/configuration/furniture.yml index f34ff47b4..3e3a2092a 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/furniture.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/furniture.yml @@ -3,7 +3,7 @@ items: material: paper custom-model-data: 2000 data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/bench" @@ -49,7 +49,7 @@ items: material: paper custom-model-data: 2001 data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/table_lamp" @@ -93,7 +93,7 @@ items: material: paper custom-model-data: 2002 data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/wooden_chair" diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/items.yml b/bukkit-loader/src/main/resources/resources/default/configuration/items.yml index ba4034232..616781886 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/items.yml @@ -6,7 +6,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz model: template: models:fishing_rod_2d @@ -22,7 +22,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz model: template: models:bow_2d @@ -42,7 +42,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz model: template: models:crossbow_2d @@ -66,7 +66,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz components: minecraft:max_damage: 64 @@ -84,7 +84,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz components: minecraft:max_damage: 64 @@ -102,7 +102,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz components: minecraft:max_damage: 64 @@ -120,7 +120,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz components: minecraft:max_damage: 64 @@ -138,7 +138,7 @@ items: tags: - "topaz_tools" data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz components: minecraft:max_damage: 64 @@ -175,7 +175,7 @@ templates: material: "chainmail_{part}" custom-model-data: 1000 data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz settings: tags: diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml b/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml index f1bdfb981..d5d84bf86 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/ores.yml @@ -3,7 +3,7 @@ items: material: paper custom-model-data: 1010 data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/topaz_ore" @@ -16,7 +16,7 @@ items: material: paper custom-model-data: 1011 data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/deepslate_topaz_ore" @@ -34,7 +34,7 @@ items: - "#topaz_tools" percent: 0.25 data: - display-name: "<#FF8C00>" + item-name: "<#FF8C00>" model: template: models:generated arguments: diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml b/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml index a17becf3a..3a33da954 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml @@ -9,7 +9,7 @@ items: - "minecraft:logs" - "minecraft:logs_that_burn" data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/palm_log" @@ -55,7 +55,7 @@ items: - "minecraft:logs" - "minecraft:logs_that_burn" data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/stripped_palm_log" @@ -98,7 +98,7 @@ items: - "minecraft:logs" - "minecraft:logs_that_burn" data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/palm_wood" @@ -144,7 +144,7 @@ items: - "minecraft:logs" - "minecraft:logs_that_burn" data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/stripped_palm_wood" @@ -186,7 +186,7 @@ items: - "minecraft:planks" - "minecraft:wooden_tool_materials" data: - display-name: "" + item-name: "" model: type: "minecraft:model" path: "minecraft:item/custom/palm_planks" @@ -218,7 +218,7 @@ items: settings: fuel-time: 100 data: - display-name: "" + item-name: "" model: template: models:generated arguments: @@ -271,7 +271,7 @@ items: material: oak_leaves custom-model-data: 1000 data: - display-name: "" + item-name: "" components: minecraft:block_state: distance: "1" diff --git a/bukkit-loader/src/main/resources/resources/internal/configuration/gui.yml b/bukkit-loader/src/main/resources/resources/internal/configuration/gui.yml index f2627ecd0..2101ee69c 100644 --- a/bukkit-loader/src/main/resources/resources/internal/configuration/gui.yml +++ b/bukkit-loader/src/main/resources/resources/internal/configuration/gui.yml @@ -65,7 +65,7 @@ templates: material: arrow custom-model-data: "{model_data}" data: - display-name: "{name}" + item-name: "{name}" lore: "{lore}" model: template: models:generated @@ -117,28 +117,28 @@ items: material: arrow custom-model-data: 1000 data: - display-name: "<#FAFAD2>" + item-name: "<#FAFAD2>" lore: - "<#F5F5F5>/" internal:next_recipe_1: material: arrow custom-model-data: 1001 data: - display-name: "<#808080>" + item-name: "<#808080>" lore: - "<#696969>/" internal:previous_recipe_0: material: arrow custom-model-data: 1002 data: - display-name: "<#FAFAD2>" + item-name: "<#FAFAD2>" lore: - "<#F5F5F5>/" internal:previous_recipe_1: material: arrow custom-model-data: 1003 data: - display-name: "<#808080>" + item-name: "<#808080>" lore: - "<#696969>/" internal:get_item: diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java index ddbad77d5..980d68725 100644 --- a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java @@ -1,8 +1,11 @@ package net.momirealms.craftengine.bukkit.util; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.PrepareAnvilEvent; import org.bukkit.inventory.AnvilInventory; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.Nullable; public class LegacyInventoryUtils { @@ -14,4 +17,17 @@ public class LegacyInventoryUtils { anvilInventory.setRepairCost(repairCost); anvilInventory.setRepairCostAmount(amount); } + + @Nullable + public static String getRenameText(AnvilInventory anvilInventory) { + return anvilInventory.getRenameText(); + } + + public static int getMaxRepairCost(AnvilInventory anvilInventory) { + return anvilInventory.getMaximumRepairCost(); + } + + public static InventoryView getView(PrepareAnvilEvent event) { + return event.getView(); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java index ed459d03a..95d371115 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java @@ -62,7 +62,7 @@ public class ComponentItemFactory extends BukkitItemFactory { } @Override - protected void displayName(ItemWrapper item, String json) { + protected void customName(ItemWrapper item, String json) { if (json == null) { item.removeComponent(ComponentKeys.CUSTOM_NAME); } else { @@ -71,7 +71,7 @@ public class ComponentItemFactory extends BukkitItemFactory { } @Override - protected Optional displayName(ItemWrapper item) { + protected Optional customName(ItemWrapper item) { if (!item.hasComponent(ComponentKeys.CUSTOM_NAME)) return Optional.empty(); return Optional.ofNullable( (String) ComponentType.encodeJava( @@ -272,4 +272,19 @@ public class ComponentItemFactory extends BukkitItemFactory { item.setComponent(ComponentKeys.MAX_STACK_SIZE, maxStackSize); } } + + @Override + protected void repairCost(ItemWrapper item, Integer data) { + if (data == null) { + item.removeComponent(ComponentKeys.REPAIR_COST); + } else { + item.setComponent(ComponentKeys.REPAIR_COST, data); + } + } + + @Override + protected Optional repairCost(ItemWrapper item) { + if (!item.hasComponent(ComponentKeys.REPAIR_COST)) return Optional.empty(); + return Optional.ofNullable((Integer) ComponentType.encodeJava(ComponentKeys.REPAIR_COST, item.getComponent(ComponentKeys.REPAIR_COST)).orElse(null)); + } } \ No newline at end of file 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 a404a5bc5..9be055d2f 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 @@ -23,7 +23,7 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected void displayName(ItemWrapper item, String json) { + protected void customName(ItemWrapper item, String json) { if (json != null) { item.set(json, "display", "Name"); } else { @@ -32,19 +32,19 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected Optional displayName(ItemWrapper item) { + protected Optional customName(ItemWrapper item) { if (!item.hasTag("display", "Name")) return Optional.empty(); return Optional.of(item.get("display", "Name")); } @Override protected void itemName(ItemWrapper item, String json) { - throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + customName(item, json); } @Override protected Optional itemName(ItemWrapper item) { - throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + return customName(item); } @Override @@ -218,4 +218,15 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected void maxStackSize(ItemWrapper item, Integer maxStackSize) { } + + @Override + protected void repairCost(ItemWrapper item, Integer data) { + item.set(data, "RepairCost"); + } + + @Override + protected Optional repairCost(ItemWrapper item) { + if (!item.hasTag("RepairCost")) return Optional.empty(); + return Optional.of(item.get("RepairCost")); + } } \ No newline at end of file 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 e6106e8d3..68315e3a2 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 @@ -1,10 +1,13 @@ package net.momirealms.craftengine.bukkit.item.recipe; import com.destroystokyo.paper.event.inventory.PrepareResultEvent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.bukkit.util.Reflections; @@ -15,10 +18,10 @@ import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Pair; import net.momirealms.craftengine.core.util.VersionHelper; @@ -459,21 +462,19 @@ public class RecipeEventListener implements Listener { return; } - // one of them is vanilla item - if (!firstCustom || !secondCustom) { - // block "vanilla + custom" recipes - if (wrappedFirst.vanillaId().equals(wrappedSecond.vanillaId())) { - event.setResult(null); - } - return; - } - // both of them are custom items // if the second is an enchanted book, then apply it if (wrappedSecond.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { return; } + // one of them is vanilla item + if (!firstCustom || !secondCustom) { + // block "vanilla + custom" recipes + event.setResult(null); + return; + } + // not the same item if (!wrappedFirst.customId().equals(wrappedSecond.customId())) { event.setResult(null); @@ -511,10 +512,12 @@ public class RecipeEventListener implements Listener { } Item wrappedFirst = BukkitItemManager.instance().wrap(first); - int damage = wrappedFirst.damage().orElse(0); + int maxDamage = wrappedFirst.maxDamage().orElse(0); // not a repairable item - if (maxDamage == 0 || damage == 0) return; + if (maxDamage == 0) return; + + int damage = wrappedFirst.damage().orElse(0); Key firstId = wrappedFirst.id(); Optional> optionalCustomTool = wrappedFirst.getCustomItem(); @@ -548,20 +551,85 @@ public class RecipeEventListener implements Listener { return; } + boolean hasResult = true; + int realDurabilityPerItem = (int) (repairItem.amount() + repairItem.percent() * maxDamage); - int consumeMaxAmount = damage / realDurabilityPerItem + 1; + int consumeMaxAmount = damage == 0 ? 0 : damage / realDurabilityPerItem + 1; int actualConsumedAmount = Math.min(consumeMaxAmount, wrappedSecond.count()); int actualRepairAmount = actualConsumedAmount * realDurabilityPerItem; int damageAfter = Math.max(damage - actualRepairAmount, 0); wrappedFirst.damage(damageAfter); - event.setResult(wrappedFirst.loadCopy()); + + String renameText; + int maxRepairCost; + if (VersionHelper.isVersionNewerThan1_21_2()) { + AnvilView anvilView = event.getView(); + renameText = anvilView.getRenameText(); + maxRepairCost = anvilView.getMaximumRepairCost(); + } else { + renameText = LegacyInventoryUtils.getRenameText(inventory); + maxRepairCost = LegacyInventoryUtils.getMaxRepairCost(inventory); + } + + int repairCost = actualConsumedAmount; + int repairPenalty = wrappedFirst.repairCost().orElse(0) + wrappedSecond.repairCost().orElse(0); + + if (renameText != null && !renameText.isBlank()) { + try { + if (!renameText.equals(Reflections.method$Component$getString.invoke(ComponentUtils.jsonToMinecraft(wrappedFirst.hoverName().orElse(AdventureHelper.EMPTY_COMPONENT))))) { + wrappedFirst.customName(AdventureHelper.componentToJson(Component.text(renameText))); + repairCost += 1; + } else if (repairCost == 0) { + hasResult = false; + System.out.println("1"); + } + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to get hover name", e); + } + } else if (VersionHelper.isVersionNewerThan1_20_5() && wrappedFirst.hasComponent(ComponentKeys.CUSTOM_NAME)) { + repairCost += 1; + wrappedFirst.customName(null); + } else if (!VersionHelper.isVersionNewerThan1_20_5() && wrappedFirst.hasTag("display", "Name")) { + repairCost += 1; + wrappedFirst.customName(null); + } + + int finalCost = repairCost + repairPenalty; + if (VersionHelper.isVersionNewerThan1_21()) { AnvilView anvilView = event.getView(); - anvilView.setRepairCost(10); + anvilView.setRepairCost(finalCost); anvilView.setRepairItemCountCost(actualConsumedAmount); } else { - LegacyInventoryUtils.setRepairCost(inventory, 10, actualRepairAmount); + LegacyInventoryUtils.setRepairCost(inventory, finalCost, actualRepairAmount); } + + Player player; + try { + player = (Player) Reflections.method$InventoryView$getPlayer.invoke(VersionHelper.isVersionNewerThan1_21() ? event.getView() : LegacyInventoryUtils.getView(event)); + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to get inventory viewer", e); + return; + } + + if (finalCost >= maxRepairCost && !plugin.adapt(player).canInstabuild()) { + hasResult = false; + } + + if (hasResult) { + int afterPenalty = wrappedFirst.repairCost().orElse(0); + int anotherPenalty = wrappedSecond.repairCost().orElse(0); + if (afterPenalty < anotherPenalty) { + afterPenalty = anotherPenalty; + } + afterPenalty = calculateIncreasedRepairCost(afterPenalty); + wrappedFirst.repairCost(afterPenalty); + event.setResult(wrappedFirst.loadCopy()); + } + } + + public static int calculateIncreasedRepairCost(int cost) { + return (int) Math.min((long) cost * 2L + 1L, 2147483647L); } // only handle repair items for the moment diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java index ac86735e0..a691c8871 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java @@ -10,6 +10,10 @@ public class ComponentUtils { public static Object adventureToMinecraft(Component component) { String json = AdventureHelper.componentToJson(component); + return jsonToMinecraft(json); + } + + public static Object jsonToMinecraft(String json) { if (VersionHelper.isVersionNewerThan1_20_5()) { try { return Reflections.method$Component$Serializer$fromJson.invoke(null, json, Reflections.instance$MinecraftRegistry); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index b4787d9e5..afc934521 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -72,6 +72,12 @@ public class Reflections { ) ); + public static final Method method$Component$getString = requireNonNull( + ReflectionUtils.getMethod( + clazz$Component, String.class, new String[]{"getString", "a"} + ) + ); + public static final Class clazz$RandomSource = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("util.RandomSource") 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 e3edb3355..eda369c0c 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 @@ -26,6 +26,17 @@ public class AbstractItem, I> implements Item { return this.factory.damage(this.item); } + @Override + public Item repairCost(Integer data) { + this.factory.repairCost(this.item, data); + return this; + } + + @Override + public Optional repairCost() { + return this.factory.repairCost(this.item); + } + @Override public Item maxDamage(Integer data) { this.factory.maxDamage(this.item, data); @@ -96,8 +107,8 @@ public class AbstractItem, I> implements Item { } @Override - public Optional displayName() { - return this.factory.displayName(this.item); + public Optional customName() { + return this.factory.customName(this.item); } @Override @@ -128,8 +139,8 @@ public class AbstractItem, I> implements Item { } @Override - public Item displayName(String displayName) { - this.factory.displayName(this.item, displayName); + public Item customName(String displayName) { + this.factory.customName(this.item, displayName); return this; } @Override 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 6969a9cd5..baa2330b1 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 @@ -168,7 +168,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl registerDataFunction((obj) -> { String name = obj.toString(); return new DisplayNameModifier<>(name); - }, "name", "display-name", "custom-name"); + }, "custom-name"); + registerDataFunction((obj) -> { + String name = obj.toString(); + return new ItemNameModifier<>(name); + }, "item-name", "display-name"); registerDataFunction((obj) -> { List name = MiscUtils.getAsStringList(obj); return new LoreModifier<>(name); @@ -197,12 +201,6 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl String pattern = data.get("pattern").toString().toLowerCase(Locale.ENGLISH); return new TrimModifier<>(material, pattern); }, "trim"); - if (VersionHelper.isVersionNewerThan1_20_5()) { - registerDataFunction((obj) -> { - String name = obj.toString(); - return new ItemNameModifier<>(name); - }, "item-name"); - } if (VersionHelper.isVersionNewerThan1_20_5()) { registerDataFunction((obj) -> { Map data = MiscUtils.castToMap(obj, false); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java index baa33752b..07779468a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java @@ -19,4 +19,5 @@ public class ComponentKeys { public static final String TOOLTIP_STYLE = Key.key("minecraft", "tooltip_style").asString(); public static final String JUKEBOX_PLAYABLE = Key.key("minecraft", "jukebox_playable").asString(); public static final String TRIM = Key.key("minecraft", "trim").asString(); + public static final String REPAIR_COST = Key.key("minecraft", "repair_cost").asString(); } 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 478f741b3..8d734326d 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 @@ -41,13 +41,21 @@ public interface Item { Optional damage(); + Item repairCost(Integer data); + + Optional repairCost(); + Item maxDamage(Integer data); Optional maxDamage(); - Item displayName(String displayName); + Item customName(String displayName); - Optional displayName(); + Optional customName(); + + default Optional hoverName() { + return customName().or(this::itemName); + } Item itemName(String itemName); 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 5a497afd4..d35dc1042 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 @@ -49,9 +49,9 @@ public abstract class ItemFactory

, I> protected abstract Optional customModelData(ItemWrapper item); - protected abstract void displayName(ItemWrapper item, String json); + protected abstract void customName(ItemWrapper item, String json); - protected abstract Optional displayName(ItemWrapper item); + protected abstract Optional customName(ItemWrapper item); protected abstract void itemName(ItemWrapper item, String json); @@ -104,4 +104,8 @@ public abstract class ItemFactory

, I> protected abstract boolean is(ItemWrapper item, Key itemTag); protected abstract boolean isBlockItem(ItemWrapper item); + + protected abstract void repairCost(ItemWrapper item, Integer data); + + protected abstract Optional repairCost(ItemWrapper item); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java index 47763231f..e73503bbb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java @@ -19,6 +19,6 @@ public class DisplayNameModifier implements ItemModifier { @Override public void apply(Item item, ItemBuildContext context) { - item.displayName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers()))); + item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers()))); } } 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 178af26ec..5cbbbd786 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 @@ -135,7 +135,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { this.plugin.logger().warn("Can't not find item " + it.icon() + " for category icon"); return null; } - item.displayName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(it.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(it.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); item.lore(it.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); item.load(); return new ItemWithAction(item, (element, click) -> { @@ -217,7 +217,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { this.plugin.logger().warn("Can't not find item " + subCategory.icon() + " for category icon"); return null; } - item.displayName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); item.load(); return new ItemWithAction(item, (element, click) -> { 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 9cb93b0ba..d75919cbc 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 @@ -17,7 +17,7 @@ import java.util.concurrent.TimeUnit; * Helper class for handling Adventure components and related functionalities. */ public class AdventureHelper { - + public static final String EMPTY_COMPONENT = componentToJson(Component.empty()); private final MiniMessage miniMessage; private final MiniMessage miniMessageStrict; private final GsonComponentSerializer gsonComponentSerializer; From d4178eb0b6fa7f50a3d1bc812bd89c96814f0742 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 16 Mar 2025 04:14:08 +0800 Subject: [PATCH 6/8] Update RecipeEventListener.java --- .../bukkit/item/recipe/RecipeEventListener.java | 7 +++---- 1 file changed, 3 insertions(+), 4 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 68315e3a2..2cdc5b1dc 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 @@ -514,10 +514,9 @@ public class RecipeEventListener implements Listener { Item wrappedFirst = BukkitItemManager.instance().wrap(first); int maxDamage = wrappedFirst.maxDamage().orElse(0); - // not a repairable item - if (maxDamage == 0) return; - int damage = wrappedFirst.damage().orElse(0); + // not a repairable item + if (damage == 0 || maxDamage == 0) return; Key firstId = wrappedFirst.id(); Optional> optionalCustomTool = wrappedFirst.getCustomItem(); @@ -554,7 +553,7 @@ public class RecipeEventListener implements Listener { boolean hasResult = true; int realDurabilityPerItem = (int) (repairItem.amount() + repairItem.percent() * maxDamage); - int consumeMaxAmount = damage == 0 ? 0 : damage / realDurabilityPerItem + 1; + int consumeMaxAmount = damage / realDurabilityPerItem + 1; int actualConsumedAmount = Math.min(consumeMaxAmount, wrappedSecond.count()); int actualRepairAmount = actualConsumedAmount * realDurabilityPerItem; int damageAfter = Math.max(damage - actualRepairAmount, 0); From 155b5b459940a22dcf2418f77b55fa244c8a519c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 16 Mar 2025 05:01:06 +0800 Subject: [PATCH 7/8] fix renaming --- .../bukkit/util/LegacyInventoryUtils.java | 9 ++++- .../item/recipe/RecipeEventListener.java | 31 ++++++++++++---- .../craftengine/bukkit/util/Reflections.java | 35 +++++++++++++++++++ .../craftengine/mod/CraftEngineBlock.java | 5 +-- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java index 980d68725..c2249eced 100644 --- a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java @@ -13,8 +13,11 @@ public class LegacyInventoryUtils { return player.getOpenInventory().getTopInventory(); } - public static void setRepairCost(AnvilInventory anvilInventory, int repairCost, int amount) { + public static void setRepairCost(AnvilInventory anvilInventory, int repairCost) { anvilInventory.setRepairCost(repairCost); + } + + public static void setRepairCostAmount(AnvilInventory anvilInventory, int amount) { anvilInventory.setRepairCostAmount(amount); } @@ -27,6 +30,10 @@ public class LegacyInventoryUtils { return anvilInventory.getMaximumRepairCost(); } + public static int getRepairCost(AnvilInventory anvilInventory) { + return anvilInventory.getRepairCost(); + } + public static InventoryView getView(PrepareAnvilEvent event) { return event.getView(); } 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 2cdc5b1dc..f84ec2cd6 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 @@ -21,10 +21,7 @@ import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.Pair; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.context.ContextHolder; import org.bukkit.Material; import org.bukkit.block.Block; @@ -561,13 +558,16 @@ public class RecipeEventListener implements Listener { String renameText; int maxRepairCost; + int previousCost; if (VersionHelper.isVersionNewerThan1_21_2()) { AnvilView anvilView = event.getView(); renameText = anvilView.getRenameText(); maxRepairCost = anvilView.getMaximumRepairCost(); + previousCost = anvilView.getRepairCost(); } else { renameText = LegacyInventoryUtils.getRenameText(inventory); maxRepairCost = LegacyInventoryUtils.getMaxRepairCost(inventory); + previousCost = LegacyInventoryUtils.getRepairCost(inventory); } int repairCost = actualConsumedAmount; @@ -580,7 +580,6 @@ public class RecipeEventListener implements Listener { repairCost += 1; } else if (repairCost == 0) { hasResult = false; - System.out.println("1"); } } catch (ReflectiveOperationException e) { plugin.logger().warn("Failed to get hover name", e); @@ -595,12 +594,32 @@ public class RecipeEventListener implements Listener { int finalCost = repairCost + repairPenalty; + if (VersionHelper.isVersionNewerThan1_21()) { + AnvilView anvilView = event.getView(); + anvilView.setRepairCost(finalCost <= 1 ? 2 : finalCost - 1); + } else { + LegacyInventoryUtils.setRepairCost(inventory, finalCost <= 1 ? 2 : finalCost - 1); + } + + try { + if (VersionHelper.isVersionNewerThan1_21()) { + Object anvilMenu = Reflections.field$CraftInventoryView$container.get(event.getView()); + Reflections.method$AbstractContainerMenu$broadcastChanges.invoke(anvilMenu); + } else { + Object anvilMenu = Reflections.field$CraftInventoryAnvil$menu.get(inventory); + Reflections.method$AbstractContainerMenu$broadcastChanges.invoke(anvilMenu); + } + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to broadcast changes", e); + } + if (VersionHelper.isVersionNewerThan1_21()) { AnvilView anvilView = event.getView(); anvilView.setRepairCost(finalCost); anvilView.setRepairItemCountCost(actualConsumedAmount); } else { - LegacyInventoryUtils.setRepairCost(inventory, finalCost, actualRepairAmount); + LegacyInventoryUtils.setRepairCost(inventory, finalCost); + LegacyInventoryUtils.setRepairCostAmount(inventory, actualConsumedAmount); } Player player; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index afc934521..e3e61867c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -4728,6 +4728,12 @@ public class Reflections { ) ); + public static final Method method$AbstractContainerMenu$broadcastChanges = requireNonNull( + ReflectionUtils.getMethod( + clazz$AbstractContainerMenu, void.class, new String[]{ "broadcastChanges", "d" } + ) + ); + public static final Class clazz$CraftContainer = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleCBClass("inventory.CraftContainer") @@ -4892,4 +4898,33 @@ public class Reflections { clazz$CraftComplexRecipe, clazz$CustomRecipe, 0 ) ); + + public static final Class clazz$CraftInventoryAnvil = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleCBClass("inventory.CraftInventoryAnvil") + ) + ); + + public static final Class clazz$AnvilMenu = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.inventory.AnvilMenu"), + BukkitReflectionUtils.assembleMCClass("world.inventory.ContainerAnvil") + ) + ); + + // 1.21+ + public static final Class clazz$CraftInventoryView = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleCBClass("inventory.CraftInventoryView") + ); + + // 1.21+ + public static final Field field$CraftInventoryView$container = Optional.ofNullable(clazz$CraftInventoryView) + .map(it -> ReflectionUtils.getDeclaredField(it, 0)).orElse(null); + + // 1.20-1.20.6 + public static final Field field$CraftInventoryAnvil$menu = + ReflectionUtils.getDeclaredField( + clazz$CraftInventoryAnvil, clazz$AnvilMenu, 0 + ); } diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java b/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java index 64afc437f..7e3b108b6 100644 --- a/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java +++ b/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java @@ -10,10 +10,7 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.BonemealableBlock; -import net.minecraft.world.level.block.Fallable; +import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.shapes.CollisionContext; From b480d7871def60c5abe65187b1182c6254502602 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 16 Mar 2025 05:15:12 +0800 Subject: [PATCH 8/8] fix visual issues --- .../bukkit/item/recipe/RecipeEventListener.java | 16 +++++----------- .../craftengine/bukkit/util/Reflections.java | 6 ++++++ 2 files changed, 11 insertions(+), 11 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 f84ec2cd6..665bbb9c4 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 @@ -594,21 +594,15 @@ public class RecipeEventListener implements Listener { int finalCost = repairCost + repairPenalty; - if (VersionHelper.isVersionNewerThan1_21()) { - AnvilView anvilView = event.getView(); - anvilView.setRepairCost(finalCost <= 1 ? 2 : finalCost - 1); - } else { - LegacyInventoryUtils.setRepairCost(inventory, finalCost <= 1 ? 2 : finalCost - 1); - } - + // To fix some client side visual issues try { + Object anvilMenu; if (VersionHelper.isVersionNewerThan1_21()) { - Object anvilMenu = Reflections.field$CraftInventoryView$container.get(event.getView()); - Reflections.method$AbstractContainerMenu$broadcastChanges.invoke(anvilMenu); + anvilMenu = Reflections.field$CraftInventoryView$container.get(event.getView()); } else { - Object anvilMenu = Reflections.field$CraftInventoryAnvil$menu.get(inventory); - Reflections.method$AbstractContainerMenu$broadcastChanges.invoke(anvilMenu); + anvilMenu = Reflections.field$CraftInventoryAnvil$menu.get(inventory); } + Reflections.method$AbstractContainerMenu$broadcastFullState.invoke(anvilMenu); } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to broadcast changes", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index e3e61867c..7e267118f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -4734,6 +4734,12 @@ public class Reflections { ) ); + public static final Method method$AbstractContainerMenu$broadcastFullState = requireNonNull( + ReflectionUtils.getMethod( + clazz$AbstractContainerMenu, void.class, new String[]{ "broadcastFullState", "e" } + ) + ); + public static final Class clazz$CraftContainer = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleCBClass("inventory.CraftContainer")