diff --git a/README.md b/README.md index 33bd80f46..ea3c73de8 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.29") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.29") + compileOnly("net.momirealms:craft-engine-core:0.0.34") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.34") } ``` diff --git a/bukkit-loader/build.gradle.kts b/bukkit-loader/build.gradle.kts index 987b566ca..eef46cabe 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-beta6" + id("com.gradleup.shadow") version "9.0.0-beta11" id("net.minecrell.plugin-yml.bukkit") version "0.6.0" } diff --git a/bukkit-loader/src/main/resources/config.yml b/bukkit-loader/src/main/resources/config.yml index 7c3c61845..125390fb7 100644 --- a/bukkit-loader/src/main/resources/config.yml +++ b/bukkit-loader/src/main/resources/config.yml @@ -26,8 +26,9 @@ resource-pack: obfuscation: enable: false seed: 0 # 0 = random seed - fake-directory: true - escape-unicode: true + fake-directory: false + escape-unicode: false + break-json: false resource-location: enable: true random-namespace: @@ -183,12 +184,14 @@ gui: title: "" smoking: title: "" - campfire: + campfire-cooking: title: "" crafting: title: "" stonecutting: title: "" + smithing-transform: + title: "" performance: # Maximum chain update depth when fixing client visuals 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 f01d4a7b7..4d152b824 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/items.yml @@ -329,4 +329,70 @@ recipes#11: B: "minecraft:stick" result: id: default:topaz_pickaxe + count: 1 + default:topaz_helmet: + type: shaped + pattern: + - "AAA" + - "A A" + ingredients: + A: "default:topaz" + result: + id: default:topaz_helmet + count: 1 + default:topaz_chestplate: + type: shaped + pattern: + - "A A" + - "AAA" + - "AAA" + ingredients: + A: "default:topaz" + result: + id: default:topaz_chestplate + count: 1 + default:topaz_leggings: + type: shaped + pattern: + - "AAA" + - "A A" + - "A A" + ingredients: + A: "default:topaz" + result: + id: default:topaz_leggings + count: 1 + default:topaz_boots: + type: shaped + pattern: + - "A A" + - "A A" + ingredients: + A: "default:topaz" + result: + id: default:topaz_boots + count: 1 + default:topaz_bow: + type: smithing_transform + base: minecraft:bow + addition: default:topaz + template-type: default:topaz + result: + id: default:topaz_bow + count: 1 + default:topaz_crossbow: + type: smithing_transform + base: minecraft:crossbow + addition: default:topaz + template-type: default:topaz + result: + id: default:topaz_crossbow + count: 1 + default:topaz_rod: + type: smithing_transform + base: minecraft:fishing_rod + addition: default:topaz + template-type: default:topaz + result: + id: default:topaz_rod count: 1 \ No newline at end of file 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 f2aefb28d..b3446fb13 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 @@ -314,12 +314,12 @@ recipes: default:palm_planks: template: default:recipe/planks arguments: - tree_type: palm + wood_type: palm default:palm_wood: template: default:recipe/log_2_wood arguments: - tree_type: palm + wood_type: palm default:stripped_palm_wood: template: default:recipe/log_2_wood arguments: - tree_type: stripped_palm \ No newline at end of file + wood_type: stripped_palm \ No newline at end of file diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/templates.yml b/bukkit-loader/src/main/resources/resources/default/configuration/templates.yml index 4a7a39aa8..d8c84f87f 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/templates.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/templates.yml @@ -33,9 +33,31 @@ templates#models#block: textures: "end": "{end_texture}" "side": "{side_texture}" + # template: default:model/cube + # arguments: + # model: model_path + # particle_texture: particle_texture_path + # down_texture: down_texture_path + # up_texture: up_texture_path + # north_texture: north_texture_path + # east_texture: east_texture_path + # south_texture: south_texture_path + # west_texture: west_texture_path + default:model/cube: + path: "{model}" + generation: + parent: "minecraft:block/cube_column" + textures: + "particle": "minecraft:block/custom/block_particle" + "down": "minecraft:block/custom/block_down" + "up": "minecraft:block/custom/block_up" + "north": "minecraft:block/custom/block_north" + "east": "minecraft:block/custom/block_east" + "south": "minecraft:block/custom/block_south" + "west": "minecraft:block/custom/block_west" # 2D items -templates#models#generated: +templates#models#2d: # template: default:model/generated # arguments: # model: model_path @@ -92,6 +114,22 @@ templates#models#generated: textures: "layer0": "{path}" +# shield +templates#models#shield: + # template: default:model/shield_3d + # arguments: + # model: shield_model_path + # block_model: shield_block_model_path + default:model/shield_3d: + type: "minecraft:condition" + property: "minecraft:using_item" + on-false: + type: minecraft:model + path: "{model}" + on-true: + type: minecraft:model + path: "{block_model}" + # fishing rods templates#models#fishing_rod: # template: default:model/fishing_rod_3d @@ -258,14 +296,14 @@ templates#models#crossbow: - when: arrow model: type: minecraft:model - path: "{arrow_path}" + path: "{arrow_model}" - when: rocket model: type: minecraft:model path: "{firework_model}" fallback: type: minecraft:model - path: "{path}" + path: "{model}" on-true: type: "minecraft:range_dispatch" property: "minecraft:crossbow/pull" @@ -305,7 +343,7 @@ templates#models#crossbow: - when: arrow model: type: minecraft:model - path: "{arrow_path}" + path: "{arrow_model}" generation: parent: "minecraft:item/crossbow_arrow" textures: @@ -320,7 +358,7 @@ templates#models#crossbow: "layer0": "{firework_texture}" fallback: type: minecraft:model - path: "{path}" + path: "{model}" generation: parent: "minecraft:item/crossbow" textures: @@ -339,7 +377,7 @@ templates#models#crossbow: threshold: 0.58 - model: type: minecraft:model - path: "{pulling_2_path}" + path: "{pulling_2_model}" generation: parent: "minecraft:item/crossbow_pulling_2" textures: @@ -862,9 +900,9 @@ templates#recipes: category: building group: planks ingredients: - A: "#default:{tree_type}_logs" + A: "#default:{wood_type}_logs" result: - id: "default:{tree_type}_planks" + id: "default:{wood_type}_planks" count: 4 default:recipe/log_2_wood: type: shaped @@ -874,9 +912,9 @@ templates#recipes: - "AA" - "AA" ingredients: - A: "default:{tree_type}_log" + A: "default:{wood_type}_log" result: - id: "default:{tree_type}_wood" + id: "default:{wood_type}_wood" count: 3 default:recipe/smelting_ore: type: smelting 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 563e589db..21bb4288d 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,7 +1,8 @@ { "texture_size": [64, 64], "textures": { - "0": "item/custom/bench" + "0": "item/custom/bench", + "particle": "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 bb2e8fdf6..25ad38f50 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,7 +1,8 @@ { "texture_size": [32, 32], "textures": { - "0": "item/custom/table_lamp" + "0": "item/custom/table_lamp", + "particle": "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 ca279830c..f1ee8e866 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,7 +1,8 @@ { "texture_size": [32, 32], "textures": { - "0": "item/custom/wooden_chair" + "0": "item/custom/wooden_chair", + "particle": "item/custom/wooden_chair" }, "elements": [ { 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 b81da6caf..7ba729dc6 100644 --- a/bukkit-loader/src/main/resources/resources/internal/configuration/gui.yml +++ b/bukkit-loader/src/main/resources/resources/internal/configuration/gui.yml @@ -53,12 +53,18 @@ images: font: minecraft:internal file: minecraft:font/gui/custom/stonecutting_recipe.png char: '\ub008' + internal:smithing_transform_recipe: + height: 142 + ascent: 20 + font: minecraft:internal + file: minecraft:font/gui/custom/smithing_transform_recipe.png + char: '\ub009' internal:no_recipe: height: 140 ascent: 18 font: minecraft:internal file: minecraft:font/gui/custom/no_recipe.png - char: '\ub009' + char: '\ub00a' templates: internal:icon/2d: diff --git a/bukkit-loader/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/smithing_transform_recipe.png b/bukkit-loader/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/smithing_transform_recipe.png new file mode 100644 index 000000000..31b6ea3e5 Binary files /dev/null and b/bukkit-loader/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/smithing_transform_recipe.png differ diff --git a/bukkit-loader/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png b/bukkit-loader/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png index 3fe5819f0..3ff743370 100644 Binary files a/bukkit-loader/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png and b/bukkit-loader/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png differ diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 4d23ac5f6..0fab7cd0e 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta6" + id("com.gradleup.shadow") version "9.0.0-beta11" id("maven-publish") } diff --git a/bukkit/legacy/build.gradle.kts b/bukkit/legacy/build.gradle.kts index 40e26ed6f..4d8b59eca 100644 --- a/bukkit/legacy/build.gradle.kts +++ b/bukkit/legacy/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("io.github.goooler.shadow") version "8.1.8" + id("com.gradleup.shadow") version "9.0.0-beta11" } repositories { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 7967d8078..b7cf50a44 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -343,9 +343,7 @@ public class BukkitFurnitureManager implements FurnitureManager { return; } Vector3f seatPos = MiscUtils.getVector3f(vector3f); - if (!furniture.releaseSeat(seatPos)) { - plugin.logger().warn("Failed to release seat " + seatPos + " for player " + player.getName()); - } + furniture.releaseSeat(seatPos); } protected boolean isSeatCarrierType(Entity entity) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/RTagItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/RTagItemWrapper.java index 46d87ddd0..b8785432b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/RTagItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/RTagItemWrapper.java @@ -4,6 +4,8 @@ import com.saicone.rtag.RtagItem; import net.momirealms.craftengine.core.item.ItemWrapper; import org.bukkit.inventory.ItemStack; +import java.util.Map; + @SuppressWarnings("UnstableApiUsage") public class RTagItemWrapper implements ItemWrapper { private final RtagItem rtagItem; @@ -110,4 +112,9 @@ public class RTagItemWrapper implements ItemWrapper { public ItemWrapper copyWithCount(int count) { return new RTagItemWrapper(new RtagItem(this.rtagItem.loadCopy()), count); } + + @Override + public Map getData() { + return this.rtagItem.get(); + } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 08717093a..be9824b72 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -88,7 +88,7 @@ public class AxeItemBehavior extends ItemBehavior { if (!InteractUtils.isInteractable(BlockStateUtils.getBlockOwnerIdFromState(state.vanillaBlockState().handle()), bukkitPlayer, BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), item - )) { + ) || player.isSecondaryUseActive()) { player.swingHand(context.getHand()); } // shrink item amount 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 95d371115..76254dea4 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 @@ -1,7 +1,11 @@ package net.momirealms.craftengine.bukkit.item.factory; +import com.saicone.rtag.RtagItem; import com.saicone.rtag.data.ComponentType; +import com.saicone.rtag.item.ItemObject; +import net.momirealms.craftengine.bukkit.item.RTagItemWrapper; import net.momirealms.craftengine.bukkit.util.EnchantmentUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.ItemWrapper; @@ -287,4 +291,18 @@ public class ComponentItemFactory extends BukkitItemFactory { 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)); } + + @Override + protected ItemWrapper merge(ItemWrapper item1, ItemWrapper item2) { + Object itemStack1 = item1.getLiteralObject(); + Object itemStack2 = item2.getLiteralObject(); + try { + Object itemStack3 = Reflections.method$ItemStack$transmuteCopy.invoke(itemStack1, Reflections.method$ItemStack$getItem.invoke(itemStack2), 1); + Reflections.method$ItemStack$applyComponents.invoke(itemStack3, Reflections.method$ItemStack$getComponentsPatch.invoke(itemStack2)); + return new RTagItemWrapper(new RtagItem(ItemObject.asCraftMirror(itemStack3)), item2.count()); + } catch (Exception e) { + this.plugin.logger().warn("Failed to merge item", e); + } + return 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 9be055d2f..98cca0794 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 @@ -1,8 +1,11 @@ package net.momirealms.craftengine.bukkit.item.factory; +import com.saicone.rtag.RtagItem; +import com.saicone.rtag.item.ItemObject; import com.saicone.rtag.tag.TagBase; import com.saicone.rtag.tag.TagCompound; import com.saicone.rtag.tag.TagList; +import net.momirealms.craftengine.bukkit.item.RTagItemWrapper; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -123,18 +126,11 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected Optional maxDamage(ItemWrapper item) { -// if (!item.hasTag("CustomFishing", "max_dur")) return Optional.empty(); -// return Optional.of(item.get("CustomFishing", "max_dur")); return Optional.of((int) item.getItem().getType().getMaxDurability()); } @Override protected void maxDamage(ItemWrapper item, Integer damage) { -// if (damage == null) { -// item.remove("CustomFishing", "max_dur"); -// } else { -// item.set(damage, "CustomFishing", "max_dur"); -// } throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); } @@ -217,6 +213,7 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected void maxStackSize(ItemWrapper item, Integer maxStackSize) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); } @Override @@ -229,4 +226,13 @@ public class UniversalItemFactory extends BukkitItemFactory { if (!item.hasTag("RepairCost")) return Optional.empty(); return Optional.of(item.get("RepairCost")); } + + @Override + protected ItemWrapper merge(ItemWrapper item1, ItemWrapper item2) { + Object itemStack = ItemObject.copy(item2.getLiteralObject()); + ItemObject.setCustomDataTag(itemStack, TagCompound.clone(ItemObject.getCustomDataTag(item1.getLiteralObject()))); + // one more step than vanilla + TagCompound.merge(ItemObject.getCustomDataTag(itemStack), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true); + return new RTagItemWrapper(new RtagItem(ItemObject.asCraftMirror(itemStack)), item2.count()); + } } \ No newline at end of file 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 bcefff087..729e2a607 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 @@ -54,6 +54,22 @@ public class BukkitRecipeManager implements RecipeManager { private static BukkitRecipeManager instance; static { + BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SMITHING_TRANSFORM, (key, recipe) -> { + CustomSmithingTransformRecipe ceRecipe = (CustomSmithingTransformRecipe) recipe; + ceRecipe.addition(); + // bukkit api doesn't allow empty material choices, that's why we do this + try { + Object smithingRecipe = createMinecraftSmithingTransformRecipe(ceRecipe); + if (VersionHelper.isVersionNewerThan1_21_2()) { + smithingRecipe = Reflections.constructor$RecipeHolder.newInstance(Reflections.method$CraftRecipe$toMinecraft.invoke(null, key), smithingRecipe); + } else if (VersionHelper.isVersionNewerThan1_20_2()) { + smithingRecipe = Reflections.constructor$RecipeHolder.newInstance(Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, key.namespace(), key.value()), smithingRecipe); + } + Reflections.method$RecipeManager$addRecipe.invoke(minecraftRecipeManager(), smithingRecipe); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to convert transform recipe", e); + } + }); BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SHAPED, (key, recipe) -> { CustomShapedRecipe ceRecipe = (CustomShapedRecipe) recipe; ShapedRecipe shapedRecipe = new ShapedRecipe(key, ceRecipe.result(ItemBuildContext.EMPTY)); @@ -65,7 +81,7 @@ public class BukkitRecipeManager implements RecipeManager { } shapedRecipe.shape(ceRecipe.pattern().pattern()); for (Map.Entry> entry : ceRecipe.pattern().ingredients().entrySet()) { - shapedRecipe.setIngredient(entry.getKey(), new RecipeChoice.MaterialChoice(ingredientToBukkitMaterials(entry.getValue()))); + shapedRecipe.setIngredient(entry.getKey(), ingredientToBukkitRecipeChoice(entry.getValue())); } try { Object craftRecipe = Reflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, shapedRecipe); @@ -85,7 +101,7 @@ public class BukkitRecipeManager implements RecipeManager { shapelessRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); } for (Ingredient ingredient : ceRecipe.ingredientsInUse()) { - shapelessRecipe.addIngredient(new RecipeChoice.MaterialChoice(ingredientToBukkitMaterials(ingredient))); + shapelessRecipe.addIngredient(ingredientToBukkitRecipeChoice(ingredient)); } try { Object craftRecipe = Reflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, shapelessRecipe); @@ -99,7 +115,7 @@ public class BukkitRecipeManager implements RecipeManager { CustomSmeltingRecipe ceRecipe = (CustomSmeltingRecipe) recipe; FurnaceRecipe furnaceRecipe = new FurnaceRecipe( key, ceRecipe.result(ItemBuildContext.EMPTY), - new RecipeChoice.MaterialChoice(ingredientToBukkitMaterials(ceRecipe.ingredient())), + ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), ceRecipe.experience(), ceRecipe.cookingTime() ); if (ceRecipe.group() != null) { @@ -120,7 +136,7 @@ public class BukkitRecipeManager implements RecipeManager { CustomSmokingRecipe ceRecipe = (CustomSmokingRecipe) recipe; SmokingRecipe smokingRecipe = new SmokingRecipe( key, ceRecipe.result(ItemBuildContext.EMPTY), - new RecipeChoice.MaterialChoice(ingredientToBukkitMaterials(ceRecipe.ingredient())), + ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), ceRecipe.experience(), ceRecipe.cookingTime() ); if (ceRecipe.group() != null) { @@ -141,7 +157,7 @@ public class BukkitRecipeManager implements RecipeManager { CustomBlastingRecipe ceRecipe = (CustomBlastingRecipe) recipe; BlastingRecipe blastingRecipe = new BlastingRecipe( key, ceRecipe.result(ItemBuildContext.EMPTY), - new RecipeChoice.MaterialChoice(ingredientToBukkitMaterials(ceRecipe.ingredient())), + ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), ceRecipe.experience(), ceRecipe.cookingTime() ); if (ceRecipe.group() != null) { @@ -162,7 +178,7 @@ public class BukkitRecipeManager implements RecipeManager { CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) recipe; CampfireRecipe campfireRecipe = new CampfireRecipe( key, ceRecipe.result(ItemBuildContext.EMPTY), - new RecipeChoice.MaterialChoice(ingredientToBukkitMaterials(ceRecipe.ingredient())), + ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), ceRecipe.experience(), ceRecipe.cookingTime() ); if (ceRecipe.group() != null) { @@ -179,7 +195,7 @@ public class BukkitRecipeManager implements RecipeManager { CraftEngine.instance().logger().warn("Failed to convert campfire recipe", e); } }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.STONE_CUTTING, (key, recipe) -> { + BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.STONECUTTING, (key, recipe) -> { CustomStoneCuttingRecipe ceRecipe = (CustomStoneCuttingRecipe) recipe; List itemStacks = new ArrayList<>(); for (Holder item : ceRecipe.ingredient().items()) { @@ -366,9 +382,13 @@ public class BukkitRecipeManager implements RecipeManager { this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe); this.byId.put(id, recipe); this.byResult.computeIfAbsent(recipe.result().item().id(), k -> new ArrayList<>()).add(recipe); + HashSet usedKeys = new HashSet<>(); for (Ingredient ingredient : recipe.ingredientsInUse()) { for (Holder holder : ingredient.items()) { - this.byIngredient.computeIfAbsent(holder.value(), k -> new ArrayList<>()).add(recipe); + Key key = holder.value(); + if (usedKeys.add(key)) { + this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); + } } } } @@ -492,6 +512,10 @@ public class BukkitRecipeManager implements RecipeManager { VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject); handleDataPackStoneCuttingRecipe(id, recipe); } + case "minecraft:smithing_transform" -> { + VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject); + handleDataPackSmithingTransform(id, recipe, (injectLogics::add)); + } } } } @@ -517,6 +541,29 @@ public class BukkitRecipeManager implements RecipeManager { return future; } + private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer materialConsumer, Consumer> holderConsumer) { + for (String item : ingredients) { + if (item.charAt(0) == '#') { + Key tag = Key.from(item.substring(1)); + for (Material material : tagToMaterials(tag)) { + materialConsumer.accept(material); + } + if (!hasCustomItemInTag) { + if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { + hasCustomItemInTag = true; + } + } + for (Holder holder : plugin.itemManager().tagToItems(tag)) { + holderConsumer.accept(holder); + } + } else { + materialConsumer.accept(MaterialUtils.getMaterial(item)); + holderConsumer.accept(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + } + } + return hasCustomItemInTag; + } + private void handleDataPackShapelessRecipe(Key id, VanillaShapelessRecipe recipe, Consumer callback) { NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createResultStack(recipe.result()); @@ -666,22 +713,7 @@ public class BukkitRecipeManager implements RecipeManager { Set materials = new HashSet<>(); Set> holders = new HashSet<>(); - boolean hasCustomItemInTag = false; - for (String item : recipe.ingredient()) { - if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - materials.addAll(tagToMaterials(tag)); - if (!hasCustomItemInTag) { - if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; - } - } - holders.addAll(plugin.itemManager().tagToItems(tag)); - } else { - materials.add(MaterialUtils.getMaterial(item)); - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); - } - } + boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), materials::add, holders::add); org.bukkit.inventory.CookingRecipe cookingRecipe = constructor1.apply(key, result, new RecipeChoice.MaterialChoice(new ArrayList<>(materials)), recipe.experience(), recipe.cookingTime()); if (recipe.group() != null) { cookingRecipe.setGroup(recipe.group()); @@ -714,6 +746,53 @@ public class BukkitRecipeManager implements RecipeManager { this.addInternalRecipe(id, ceRecipe); } + private void handleDataPackSmithingTransform(Key id, VanillaSmithingTransformRecipe recipe, Consumer callback) { + NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); + ItemStack result = createResultStack(recipe.result()); + boolean hasCustomItemInTag; + + Set additionMaterials = new HashSet<>(); + Set> additionHolders = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionMaterials::add, additionHolders::add); + + Set templateMaterials = new HashSet<>(); + Set> templateHolders = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateMaterials::add, templateHolders::add); + + Set baseMaterials = new HashSet<>(); + Set> baseHolders = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseMaterials::add, 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()), result), recipe.result().count()), + true, + List.of() + ); + + SmithingTransformRecipe transformRecipe = new SmithingTransformRecipe(key, result, + new RecipeChoice.MaterialChoice(new ArrayList<>(templateMaterials)), + new RecipeChoice.MaterialChoice(new ArrayList<>(baseMaterials)), + new RecipeChoice.MaterialChoice(new ArrayList<>(additionMaterials)) + ); + + if (hasCustomItemInTag) { + callback.accept(() -> { + try { + unregisterRecipe(key); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(Reflections.method$CraftSmithingTransformRecipe$fromBukkitRecipe.invoke(null, transformRecipe)); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to convert transform recipe", e); + } + }); + this.injectedDataPackRecipes.add(key); + } + this.addInternalRecipe(id, ceRecipe); + } + private List tagToMaterials(Key tag) { Set materials = new HashSet<>(); List> holders = this.plugin.itemManager().tagToVanillaItems(tag); @@ -763,12 +842,12 @@ public class BukkitRecipeManager implements RecipeManager { return Key.of(prefix, fileName); } - private static List ingredientToBukkitMaterials(Ingredient ingredient) { + private static RecipeChoice ingredientToBukkitRecipeChoice(Ingredient ingredient) { Set materials = new HashSet<>(); for (Holder holder : ingredient.items()) { materials.add(getMaterialById(holder.value())); } - return new ArrayList<>(materials); + return new RecipeChoice.MaterialChoice(new ArrayList<>(materials)); } private static Material getMaterialById(Key key) { @@ -888,6 +967,53 @@ public class BukkitRecipeManager implements RecipeManager { } } + // 1.20-1.21.2 + private static Object toMinecraftIngredient(Ingredient ingredient) throws ReflectiveOperationException { + if (ingredient == null) { + return Reflections.method$CraftRecipe$toIngredient.invoke(null, null, true); + } else { + RecipeChoice choice = ingredientToBukkitRecipeChoice(ingredient); + return Reflections.method$CraftRecipe$toIngredient.invoke(null, choice, true); + } + } + + // 1.21.2+ + private static Optional toOptionalMinecraftIngredient(Ingredient ingredient) throws ReflectiveOperationException { + if (ingredient == null) { + return Optional.empty(); + } else { + RecipeChoice choice = ingredientToBukkitRecipeChoice(ingredient); + Object mcIngredient = Reflections.method$CraftRecipe$toIngredient.invoke(null, choice, true); + return Optional.of(mcIngredient); + } + } + + private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe ceRecipe) throws ReflectiveOperationException { + if (VersionHelper.isVersionNewerThan1_21_2()) { + return Reflections.constructor$SmithingTransformRecipe.newInstance( + toOptionalMinecraftIngredient(ceRecipe.template()), + toOptionalMinecraftIngredient(ceRecipe.base()), + toOptionalMinecraftIngredient(ceRecipe.addition()), + Reflections.method$CraftItemStack$asNMSMirror.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + ); + } else if (VersionHelper.isVersionNewerThan1_20_2()) { + return Reflections.constructor$SmithingTransformRecipe.newInstance( + toMinecraftIngredient(ceRecipe.template()), + toMinecraftIngredient(ceRecipe.base()), + toMinecraftIngredient(ceRecipe.addition()), + Reflections.method$CraftItemStack$asNMSMirror.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + ); + } else { + return Reflections.constructor$SmithingTransformRecipe.newInstance( + Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, ceRecipe.id().namespace(), ceRecipe.id().value()), + toMinecraftIngredient(ceRecipe.template()), + toMinecraftIngredient(ceRecipe.base()), + toMinecraftIngredient(ceRecipe.addition()), + Reflections.method$CraftItemStack$asNMSMirror.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + ); + } + } + public Object getRecipeHolderByRecipe(Recipe recipe) { return recipeToMcRecipeHolder.get(recipe); } 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 545134541..f6b0518cb 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 @@ -11,12 +11,11 @@ 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.*; -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.*; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; +import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -38,6 +37,7 @@ import org.bukkit.event.inventory.*; 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; @@ -832,4 +832,71 @@ public class RecipeEventListener implements Listener { plugin.logger().warn("Failed to correct used recipe", e); } } + + @EventHandler(ignoreCancelled = true) + public void onSmithingTransform(PrepareSmithingEvent event) { + if (!ConfigManager.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) { + return; + } + + ItemStack base = inventory.getInputEquipment(); + ItemStack template = inventory.getInputTemplate(); + ItemStack addition = inventory.getInputMineral(); + + SmithingInput input = new SmithingInput<>( + getOptimizedIDItem(base), + getOptimizedIDItem(template), + getOptimizedIDItem(addition) + ); + + Recipe ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SMITHING_TRANSFORM, input); + if (ceRecipe == null) { + event.setResult(null); + return; + } + + Player player; + try { + player = (Player) Reflections.method$InventoryView$getPlayer.invoke(event.getView()); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to get inventory viewer", e); + return; + } + + CustomSmithingTransformRecipe transformRecipe = (CustomSmithingTransformRecipe) ceRecipe; + ItemStack processed = transformRecipe.assemble(new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY), this.itemManager.wrap(base)); + event.setResult(processed); + correctSmithingRecipeUsed(inventory, ceRecipe); + } + + private void correctSmithingRecipeUsed(SmithingInventory inventory, Recipe recipe) { + Object holderOrRecipe = recipeManager.getRecipeHolderByRecipe(recipe); + if (holderOrRecipe == null) { + // it's a vanilla recipe but not injected + return; + } + try { + Object resultInventory = Reflections.field$CraftResultInventory$resultInventory.get(inventory); + Reflections.field$ResultContainer$recipeUsed.set(resultInventory, holderOrRecipe); + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to correct used recipe", e); + } + } + + private OptimizedIDItem getOptimizedIDItem(@Nullable ItemStack itemStack) { + if (ItemUtils.isEmpty(itemStack)) { + return EMPTY; + } else { + Item wrappedItem = this.itemManager.wrap(itemStack); + Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); + return idHolder.map(keyReference -> new OptimizedIDItem<>(keyReference, itemStack)).orElse(EMPTY); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 1dba5c41c..a7614305e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -85,8 +85,6 @@ public class BukkitInjector { public static void init() { try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - clazz$InjectedCacheChecker = byteBuddy .subclass(Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) .implement(Reflections.clazz$RecipeManager$CachedCheck) @@ -349,7 +347,7 @@ public class BukkitInjector { boolean isCustom = recipeManager.isCustomRecipe(recipeId); if (!isCustom) { field$InjectedCacheChecker$lastRecipe.set(thisObj, resourceLocation); - return optionalRecipe; + return Optional.of(pair.getSecond()); } Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); 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 7e267118f..0e474bebd 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 @@ -4125,6 +4125,18 @@ public class Reflections { ) ); + public static final Class clazz$CraftSmithingTransformRecipe = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleCBClass("inventory.CraftSmithingTransformRecipe") + ) + ); + + public static final Method method$CraftSmithingTransformRecipe$fromBukkitRecipe = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$CraftSmithingTransformRecipe, clazz$CraftSmithingTransformRecipe, SmithingTransformRecipe.class + ) + ); + public static final Class clazz$FeatureFlagSet = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("world.flag.FeatureFlagSet") @@ -4255,6 +4267,12 @@ public class Reflections { BukkitReflectionUtils.assembleMCClass("world.item.crafting.RecipeHolder") ); + // 1.20.2-1.21.1 resource location + // 1.21.2+ resource key + public static final Constructor constructor$RecipeHolder = Optional.ofNullable(clazz$RecipeHolder) + .map(it -> ReflectionUtils.getConstructor(it, 0)) + .orElse(null); + // 1.20.2+ public static final Field field$RecipeHolder$recipe = Optional.ofNullable(clazz$RecipeHolder) .map(it -> ReflectionUtils.getDeclaredField(it, 1)) @@ -4396,6 +4414,18 @@ public class Reflections { ) ); + public static final Class clazz$CraftResultInventory = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleCBClass("inventory.CraftResultInventory") + ) + ); + + public static final Field field$CraftResultInventory$resultInventory = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$CraftResultInventory, clazz$Container, 0 + ) + ); + // 1.20.5+ public static final Method method$ItemStack$hurtAndBreak = ReflectionUtils.getMethod( @@ -4933,4 +4963,56 @@ public class Reflections { ReflectionUtils.getDeclaredField( clazz$CraftInventoryAnvil, clazz$AnvilMenu, 0 ); + + public static final Class clazz$SmithingTransformRecipe = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.item.crafting.SmithingTransformRecipe") + ) + ); + + public static final Constructor constructor$SmithingTransformRecipe = requireNonNull( + VersionHelper.isVersionNewerThan1_21_2() ? + ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack) : + VersionHelper.isVersionNewerThan1_20_2() ? + ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) : + ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) + ); + + public static final Method method$RecipeManager$addRecipe = requireNonNull( + VersionHelper.isVersionNewerThan1_20_2() ? + ReflectionUtils.getMethod(clazz$RecipeManager, void.class, clazz$RecipeHolder) : + ReflectionUtils.getMethod(clazz$RecipeManager, void.class, clazz$Recipe) + ); + + public static final Method method$CraftRecipe$toIngredient = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$CraftRecipe, clazz$Ingredient, RecipeChoice.class, boolean.class + ) + ); + + // 1.20.5+ + public static final Method method$ItemStack$transmuteCopy = ReflectionUtils.getMethod( + clazz$ItemStack, clazz$ItemStack, clazz$ItemLike, int.class + ); + + // 1.20.5+ + public static final Class clazz$DataComponentPatch = ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("core.component.DataComponentPatch") + ); + + // 1.20.5+ + public static final Method method$ItemStack$getComponentsPatch = Optional.ofNullable(clazz$DataComponentPatch) + .map(it -> ReflectionUtils.getMethod(clazz$ItemStack, it)) + .orElse(null); + + // 1.20.5+ + public static final Method method$ItemStack$applyComponents = Optional.ofNullable(clazz$DataComponentPatch) + .map(it -> ReflectionUtils.getMethod(clazz$ItemStack, void.class, it)) + .orElse(null); + + public static final Method method$ItemStack$getItem = requireNonNull( + ReflectionUtils.getMethod( + clazz$ItemStack, clazz$Item + ) + ); } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 04d5bd3dc..5099cf31c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta6" + id("com.gradleup.shadow") version "9.0.0-beta11" id("maven-publish") } 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 eda369c0c..ae652add7 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 @@ -143,6 +143,7 @@ public class AbstractItem, I> implements Item { this.factory.customName(this.item, displayName); return this; } + @Override public Item itemName(String itemName) { this.factory.itemName(this.item, itemName); @@ -276,4 +277,10 @@ public class AbstractItem, I> implements Item { public Object getLiteralObject() { return this.item.getLiteralObject(); } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Item merge(Item another) { + return new AbstractItem<>(this.factory, this.factory.merge(this.item, ((AbstractItem) another).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 8d734326d..7de763c22 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 @@ -116,4 +116,6 @@ public interface Item { boolean is(Key itemTag); Object getLiteralObject(); + + Item merge(Item another); } 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 d35dc1042..c5595bef9 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 @@ -108,4 +108,6 @@ public abstract class ItemFactory

, I> protected abstract void repairCost(ItemWrapper item, Integer data); protected abstract Optional repairCost(ItemWrapper item); + + protected abstract ItemWrapper merge(ItemWrapper item1, ItemWrapper item2); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java index 49af43621..241ac787e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.item; +import java.util.Map; + public interface ItemWrapper { I getItem(); @@ -37,4 +39,6 @@ public interface ItemWrapper { void count(int amount); ItemWrapper copyWithCount(int count); + + Map getData(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java similarity index 82% rename from core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipe.java rename to core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java index 96ecf0394..a1e5e3303 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java @@ -4,18 +4,17 @@ import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; -public abstract class AbstractRecipe implements Recipe { +public abstract class AbstractGroupedRecipe implements Recipe { protected final String group; protected final Key id; protected final CustomRecipeResult result; - protected AbstractRecipe(Key id, String group, CustomRecipeResult result) { + protected AbstractGroupedRecipe(Key id, String group, CustomRecipeResult result) { this.group = group; this.id = id; this.result = result; } - @Override @Nullable public String group() { return group; 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 673212f9a..8d80181ec 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 @@ -21,11 +21,11 @@ public class CustomBlastingRecipe extends CustomCookingRecipe { return RecipeTypes.BLASTING; } - public static class Factory implements RecipeFactory> { + public static class Factory implements RecipeFactory { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe> create(Key id, Map arguments) { + public Recipe create(Key id, Map arguments) { CookingRecipeCategory recipeCategory = arguments.containsKey("category") ? CookingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = MiscUtils.getAsInt(arguments.getOrDefault("time", 80)); 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 7045774fb..fd3220981 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 @@ -21,11 +21,11 @@ public class CustomCampfireRecipe extends CustomCookingRecipe { return RecipeTypes.CAMPFIRE_COOKING; } - public static class Factory implements RecipeFactory> { + public static class Factory implements RecipeFactory { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe> create(Key id, Map arguments) { + public Recipe create(Key id, Map arguments) { CookingRecipeCategory recipeCategory = arguments.containsKey("category") ? CookingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = MiscUtils.getAsInt(arguments.getOrDefault("time", 80)); 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 971e51a34..423470eb1 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 @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.util.Key; import java.util.List; -public abstract class CustomCookingRecipe extends AbstractRecipe { +public abstract class CustomCookingRecipe extends AbstractGroupedRecipe { protected final CookingRecipeCategory category; protected final Ingredient ingredient; protected final float experience; 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 aaa19bc49..866a2db07 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 @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.util.Key; -public abstract class CustomCraftingTableRecipe extends AbstractRecipe { +public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe { protected final CraftingRecipeCategory category; protected CustomCraftingTableRecipe(Key id, CraftingRecipeCategory category, String group, CustomRecipeResult 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 dbc3c5039..7f4fed503 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 @@ -21,11 +21,11 @@ public class CustomSmeltingRecipe extends CustomCookingRecipe { return RecipeTypes.SMELTING; } - public static class Factory implements RecipeFactory> { + public static class Factory implements RecipeFactory { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe> create(Key id, Map arguments) { + public Recipe create(Key id, Map arguments) { CookingRecipeCategory recipeCategory = arguments.containsKey("category") ? CookingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = MiscUtils.getAsInt(arguments.getOrDefault("time", 80)); 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 new file mode 100644 index 000000000..5dbe5a725 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -0,0 +1,200 @@ +package net.momirealms.craftengine.core.item.recipe; + +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.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +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.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceKey; +import net.momirealms.craftengine.core.util.TriConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class CustomSmithingTransformRecipe implements Recipe { + public static final Factory FACTORY = new Factory<>(); + private final Key id; + private final CustomRecipeResult result; + private final Ingredient base; + private final Ingredient template; + private final Ingredient addition; + private final boolean mergeComponents; + private final List processors; + + public CustomSmithingTransformRecipe(Key id, + @Nullable Ingredient base, + @Nullable Ingredient template, + @Nullable Ingredient addition, + CustomRecipeResult result, + boolean mergeComponents, + List processors + ) { + this.id = id; + this.result = result; + this.base = base; + this.template = template; + this.addition = addition; + this.processors = processors; + this.mergeComponents = mergeComponents; + } + + @SuppressWarnings("unchecked") + @Override + public boolean matches(RecipeInput input) { + SmithingInput smithingInput = (SmithingInput) input; + return checkIngredient(this.base, smithingInput.base()) + && checkIngredient(this.template, smithingInput.template()) + && checkIngredient(this.addition, smithingInput.addition()); + } + + private boolean checkIngredient(Ingredient ingredient, OptimizedIDItem item) { + if (ingredient != null) { + if (item == null || item.isEmpty()) { + return false; + } + return ingredient.test(item); + } else { + return item == null || item.isEmpty(); + } + } + + @Override + public List> ingredientsInUse() { + List> ingredients = new ArrayList<>(); + ingredients.add(this.base); + if (this.template != null) { + ingredients.add(this.template); + } + if (this.addition != null) { + ingredients.add(this.addition); + } + return ingredients; + } + + @Override + public @NotNull Key type() { + return RecipeTypes.SMITHING_TRANSFORM; + } + + @Override + public Key id() { + return this.id; + } + + @Override + public T result(ItemBuildContext context) { + return this.result.buildItemStack(context); + } + + @SuppressWarnings("unchecked") + public T assemble(ItemBuildContext context, Item base) { + T result = this.result(context); + Item wrappedResult = (Item) CraftEngine.instance().itemManager().wrap(result); + Item finalResult = wrappedResult; + if (this.mergeComponents) { + finalResult = base.merge(wrappedResult); + } + for (ItemDataProcessor processor : this.processors) { + processor.accept(base, wrappedResult, finalResult); + } + return finalResult.load(); + } + + @Override + public CustomRecipeResult result() { + return this.result; + } + + @Nullable + public Ingredient base() { + return this.base; + } + + @Nullable + public Ingredient template() { + return template; + } + + @Nullable + public Ingredient addition() { + return addition; + } + + @SuppressWarnings({"DuplicatedCode"}) + public static class Factory implements RecipeFactory { + + @Override + public Recipe create(Key id, Map arguments) { + List base = MiscUtils.getAsStringList(arguments.get("base")); + List addition = MiscUtils.getAsStringList(arguments.get("addition")); + List template = MiscUtils.getAsStringList(arguments.get("template-type")); + boolean mergeComponents = (boolean) arguments.getOrDefault("merge-components", true); + @SuppressWarnings("unchecked") + List> processors = (List>) arguments.getOrDefault("post-processors", List.of()); + return new CustomSmithingTransformRecipe<>( + id, + toIngredient(base), toIngredient(template),toIngredient(addition), parseResult(arguments), + mergeComponents, + ItemDataProcessors.fromMapList(processors) + ); + } + + private 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(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow(() -> new IllegalArgumentException("Invalid vanilla/custom item: " + item))); + } + } + return holders.isEmpty() ? null : Ingredient.of(holders); + } + } + + public static class ItemDataProcessors { + + public static List fromMapList(List> mapList) { + if (mapList == null || mapList.isEmpty()) return List.of(); + List functions = new ArrayList<>(); + for (Map map : mapList) { + functions.add(fromMap(map)); + } + return functions; + } + + public static ItemDataProcessor fromMap(Map map) { + String type = (String) map.get("type"); + if (type == null) { + throw new NullPointerException("processor type cannot be null"); + } + Key key = Key.withDefaultNamespace(type, "craftengine"); + ItemDataProcessor.Factory factory = BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY.getValue(key); + if (factory == null) { + throw new IllegalArgumentException("Unknown processor type: " + type); + } + return factory.create(map); + } + + public static void register(Key key, ItemDataProcessor.Factory factory) { + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.SMITHING_RESULT_PROCESSOR_FACTORY.location(), key)); + holder.bindValue(factory); + } + } + + @FunctionalInterface + public interface ItemDataProcessor extends TriConsumer, Item, Item> { + + interface Factory { + ItemDataProcessor create(Map arguments); + } + } +} 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 bb243c90d..2976836e0 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 @@ -21,11 +21,11 @@ public class CustomSmokingRecipe extends CustomCookingRecipe { return RecipeTypes.SMOKING; } - public static class Factory implements RecipeFactory> { + public static class Factory implements RecipeFactory { @SuppressWarnings({"unchecked", "rawtypes", "DuplicatedCode"}) @Override - public Recipe> create(Key id, Map arguments) { + public Recipe create(Key id, Map arguments) { CookingRecipeCategory recipeCategory = arguments.containsKey("category") ? CookingRecipeCategory.valueOf(arguments.get("category").toString().toUpperCase(Locale.ENGLISH)) : null; String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = MiscUtils.getAsInt(arguments.getOrDefault("time", 80)); 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 1c14ee66e..bc0cbc901 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 @@ -14,7 +14,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -public class CustomStoneCuttingRecipe extends AbstractRecipe { +public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { public static final Factory FACTORY = new Factory<>(); protected final Ingredient ingredient; @@ -36,7 +36,7 @@ public class CustomStoneCuttingRecipe extends AbstractRecipe { @Override public @NotNull Key type() { - return RecipeTypes.STONE_CUTTING; + return RecipeTypes.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 1e99f00ca..befd2940a 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 @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; @@ -22,7 +21,4 @@ public interface Recipe { Key type(); Key id(); - - @Nullable - String group(); } 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 e350f5111..4f9b7a047 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 @@ -16,7 +16,9 @@ public class RecipeTypes { public static final Key BLASTING = Key.of("minecraft:blasting"); public static final Key SMOKING = Key.of("minecraft:smoking"); public static final Key CAMPFIRE_COOKING = Key.of("minecraft:campfire_cooking"); - public static final Key STONE_CUTTING = Key.of("minecraft:stone_cutting"); + public static final Key STONECUTTING = Key.of("minecraft:stonecutting"); + public static final Key SMITHING_TRANSFORM = Key.of("minecraft:smithing_transform"); + public static final Key SMITHING_TRIM = Key.of("minecraft:smithing_trim"); static { register(SHAPED, CustomShapedRecipe.FACTORY); @@ -25,7 +27,8 @@ public class RecipeTypes { register(SMOKING, CustomSmokingRecipe.FACTORY); register(BLASTING, CustomBlastingRecipe.FACTORY); register(CAMPFIRE_COOKING, CustomCampfireRecipe.FACTORY); - register(STONE_CUTTING, CustomStoneCuttingRecipe.FACTORY); + register(STONECUTTING, CustomStoneCuttingRecipe.FACTORY); + register(SMITHING_TRANSFORM, CustomSmithingTransformRecipe.FACTORY); } public static void register(Key key, RecipeFactory factory) { 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 new file mode 100644 index 000000000..29764fcb5 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.item.recipe.input; + +import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; +import org.jetbrains.annotations.Nullable; + +public class SmithingInput implements RecipeInput { + private final OptimizedIDItem base; + private final OptimizedIDItem template; + private final OptimizedIDItem addition; + + public SmithingInput(@Nullable OptimizedIDItem base, + @Nullable OptimizedIDItem template, + @Nullable OptimizedIDItem addition) { + this.base = base; + this.template = template; + this.addition = addition; + } + + @Nullable + public OptimizedIDItem base() { + return base; + } + + @Nullable + public OptimizedIDItem template() { + return template; + } + + @Nullable + public OptimizedIDItem addition() { + return addition; + } +} 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 9e6775d69..a78b6bb0c 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,8 @@ 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.util.Key; import java.util.List; @@ -9,4 +11,9 @@ public class VanillaBlastingRecipe extends VanillaCookingRecipe { public VanillaBlastingRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } + + @Override + public Key type() { + return RecipeTypes.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 b2d8cae30..aa12d79db 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,8 @@ 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.util.Key; import java.util.List; @@ -9,4 +11,9 @@ public class VanillaCampfireRecipe extends VanillaCookingRecipe { public VanillaCampfireRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } + + @Override + public Key type() { + return RecipeTypes.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 index 594d372ac..93d91f943 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 @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; import java.util.List; -public abstract class VanillaCookingRecipe extends VanillaRecipe { +public abstract class VanillaCookingRecipe extends VanillaGroupedRecipe { protected final List ingredient; protected final CookingRecipeCategory category; protected final float 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 2ba1d3c09..d8cd3bdb5 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 @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; -public class VanillaCraftingRecipe extends VanillaRecipe { +public abstract class VanillaCraftingRecipe extends VanillaGroupedRecipe { protected final CraftingRecipeCategory category; protected VanillaCraftingRecipe(CraftingRecipeCategory category, String group, RecipeResult result) { 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 new file mode 100644 index 000000000..813a35e34 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java @@ -0,0 +1,20 @@ +package net.momirealms.craftengine.core.item.recipe.vanilla; + +public abstract class VanillaGroupedRecipe implements VanillaRecipe { + protected final String group; + protected final RecipeResult result; + + protected VanillaGroupedRecipe(String group, RecipeResult result) { + this.group = group; + this.result = result; + } + + public String group() { + return group; + } + + @Override + public RecipeResult 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 index 000077538..d020f5a69 100644 --- 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 @@ -1,19 +1,10 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; -public abstract class VanillaRecipe { - protected final String group; - protected final RecipeResult result; +import net.momirealms.craftengine.core.util.Key; - protected VanillaRecipe(String group, RecipeResult result) { - this.group = group; - this.result = result; - } +public interface VanillaRecipe { - public String group() { - return group; - } + Key type(); - public RecipeResult result() { - return result; - } + RecipeResult 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 2f534efb1..f75e42eea 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 @@ -17,4 +17,6 @@ public interface VanillaRecipeReader { VanillaCampfireRecipe readCampfire(JsonObject json); VanillaStoneCuttingRecipe readStoneCutting(JsonObject json); + + VanillaSmithingTransformRecipe readSmithingTransform(JsonObject 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 3b8f5d127..753590f5c 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,8 @@ 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.util.Key; import java.util.List; import java.util.Map; @@ -26,4 +28,9 @@ public class VanillaShapedRecipe extends VanillaCraftingRecipe { public String[] pattern() { return pattern; } + + @Override + public Key type() { + return RecipeTypes.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 613a2f7e8..2e06b2988 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,8 @@ 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.util.Key; import java.util.List; @@ -15,4 +17,9 @@ public class VanillaShapelessRecipe extends VanillaCraftingRecipe { public List> ingredients() { return ingredients; } + + @Override + public Key type() { + return RecipeTypes.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 5aa346c26..ebbed4b21 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,8 @@ 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.util.Key; import java.util.List; @@ -9,4 +11,9 @@ public class VanillaSmeltingRecipe extends VanillaCookingRecipe { public VanillaSmeltingRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } + + @Override + public Key type() { + return RecipeTypes.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 new file mode 100644 index 000000000..6ad75f38e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java @@ -0,0 +1,42 @@ +package net.momirealms.craftengine.core.item.recipe.vanilla; + +import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.util.Key; + +import java.util.List; + +public class VanillaSmithingTransformRecipe implements VanillaRecipe { + private final RecipeResult result; + private final List base; + private final List template; + private final List addition; + + public VanillaSmithingTransformRecipe(List base, List template, List addition, RecipeResult result) { + this.result = result; + this.base = base; + this.template = template; + this.addition = addition; + } + + @Override + public Key type() { + return RecipeTypes.SMITHING_TRANSFORM; + } + + @Override + public RecipeResult 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/VanillaSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmokingRecipe.java index df919f810..736a3fd5e 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,8 @@ 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.util.Key; import java.util.List; @@ -9,4 +11,9 @@ public class VanillaSmokingRecipe extends VanillaCookingRecipe { public VanillaSmokingRecipe(CookingRecipeCategory category, String group, RecipeResult result, List ingredient, float experience, int cookingTime) { super(category, group, result, ingredient, experience, cookingTime); } + + @Override + public Key type() { + return RecipeTypes.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 79ab56d86..864557c68 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,8 +1,11 @@ package net.momirealms.craftengine.core.item.recipe.vanilla; +import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.util.Key; + import java.util.List; -public class VanillaStoneCuttingRecipe extends VanillaRecipe { +public class VanillaStoneCuttingRecipe extends VanillaGroupedRecipe { private final List ingredient; public VanillaStoneCuttingRecipe(String group, RecipeResult result, List ingredient) { @@ -13,4 +16,9 @@ public class VanillaStoneCuttingRecipe extends VanillaRecipe { public List ingredient() { return ingredient; } + + @Override + public Key type() { + return RecipeTypes.STONECUTTING; + } } 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 index c6897a43c..ff836a317 100644 --- 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 @@ -91,6 +91,16 @@ public class VanillaRecipeReader1_20 extends AbstractRecipeReader { ); } + @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")) + ); + } + protected List readSingleIngredient(JsonElement json) { List ingredients = new ArrayList<>(); if (json.isJsonObject()) { @@ -126,6 +136,12 @@ public class VanillaRecipeReader1_20 extends AbstractRecipeReader { 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) { 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 index 727ba41cb..3bd399f96 100644 --- 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 @@ -26,4 +26,9 @@ public class VanillaRecipeReader1_20_5 extends VanillaRecipeReader1_20 { 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/loot/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java index 9fc14c68e..45ec409e9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java @@ -26,7 +26,7 @@ public class NumberProviders { holder.bindValue(factory); } - static List fromMapList(List> mapList) { + public static List fromMapList(List> mapList) { if (mapList == null || mapList.isEmpty()) return List.of(); List functions = new ArrayList<>(); for (Map map : mapList) { 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 359bd76bd..c67945b43 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 @@ -249,6 +249,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/smelting.png"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/campfire.png"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png"); + plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/smithing_transform_recipe.png"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/cooking_recipe.png"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/crafting_recipe.png"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/no_recipe.png"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java index 9490ece90..2e449ac12 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java @@ -54,6 +54,7 @@ public class ConfigManager implements Reloadable { protected long resource_pack$protection$obfuscation$seed; protected boolean resource_pack$protection$obfuscation$fake_directory; protected boolean resource_pack$protection$obfuscation$escape_unicode; + protected boolean resource_pack$protection$obfuscation$break_json; protected boolean resource_pack$protection$obfuscation$resource_location$enable; protected int resource_pack$protection$obfuscation$resource_location$random_namespace$length; protected int resource_pack$protection$obfuscation$resource_location$random_namespace$amount; @@ -200,6 +201,7 @@ public class ConfigManager implements Reloadable { resource_pack$protection$obfuscation$seed = config.getLong("resource-pack.protection.obfuscation.seed", 0L); resource_pack$protection$obfuscation$fake_directory = config.getBoolean("resource-pack.protection.obfuscation.fake-directory", false); resource_pack$protection$obfuscation$escape_unicode = config.getBoolean("resource-pack.protection.obfuscation.escape-unicode", false); + resource_pack$protection$obfuscation$break_json = config.getBoolean("resource-pack.protection.obfuscation.break-json", false); resource_pack$protection$obfuscation$resource_location$enable = config.getBoolean("resource-pack.protection.obfuscation.resource-location.enable", false); resource_pack$protection$obfuscation$resource_location$random_namespace$amount = config.getInt("resource-pack.protection.obfuscation.resource-location.random-namespace.amount", 32); @@ -435,6 +437,10 @@ public class ConfigManager implements Reloadable { return instance.resource_pack$protection$obfuscation$escape_unicode; } + public static boolean breakJson() { + return instance.resource_pack$protection$obfuscation$break_json; + } + public static boolean enableRandomResourceLocation() { return instance.resource_pack$protection$obfuscation$resource_location$enable; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java index 222136c53..9586fb7ad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java @@ -65,6 +65,7 @@ public interface ItemBrowserManager extends Reloadable, ConfigSectionParser { public static String RECIPE_CAMPFIRE_TITLE; public static String RECIPE_CRAFTING_TITLE; public static String RECIPE_STONECUTTING_TITLE; + public static String RECIPE_SMITHING_TRANSFORM_TITLE; public static Key RECIPE_BACK; public static Key RECIPE_EXIT; public static Key RECIPE_NEXT_PAGE_AVAILABLE; @@ -100,9 +101,10 @@ public interface ItemBrowserManager extends Reloadable, ConfigSectionParser { RECIPE_BLASTING_TITLE = getOrThrow(section, "recipe.blasting.title"); RECIPE_SMELTING_TITLE = getOrThrow(section, "recipe.smelting.title"); RECIPE_SMOKING_TITLE = getOrThrow(section, "recipe.smoking.title"); - RECIPE_CAMPFIRE_TITLE = getOrThrow(section, "recipe.campfire.title"); + RECIPE_CAMPFIRE_TITLE = getOrThrow(section, "recipe.campfire-cooking.title"); RECIPE_CRAFTING_TITLE = getOrThrow(section, "recipe.crafting.title"); RECIPE_STONECUTTING_TITLE = getOrThrow(section, "recipe.stonecutting.title"); + RECIPE_SMITHING_TRANSFORM_TITLE = getOrThrow(section, "recipe.smithing-transform.title"); RECIPE_BACK = Key.of(getOrThrow(section, "recipe.page-navigation.return")); RECIPE_EXIT = Key.of(getOrThrow(section, "recipe.page-navigation.exit")); RECIPE_NEXT_PAGE_AVAILABLE = Key.of(getOrThrow(section, "recipe.page-navigation.next.available")); 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 5742fe02d..2b203b19d 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 @@ -349,10 +349,215 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openCookingRecipePage(player, (CustomCookingRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); return; } - if (recipeType == RecipeTypes.STONE_CUTTING) { + if (recipeType == RecipeTypes.STONECUTTING) { openStoneCuttingRecipePage(player, (CustomStoneCuttingRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); return; } + if (recipeType == RecipeTypes.SMITHING_TRANSFORM) { + openSmithingTransformRecipePage(player, (CustomSmithingTransformRecipe) recipe, parentGui, recipes, index, depth, canOpenNoRecipePage); + return; + } + } + + public void openSmithingTransformRecipePage(Player player, CustomSmithingTransformRecipe recipe, Gui parentGui, List> recipes, int index, int depth, boolean canOpenNoRecipePage) { + Key previous = index > 0 ? Constants.RECIPE_PREVIOUS_PAGE_AVAILABLE : Constants.RECIPE_PREVIOUS_PAGE_BLOCK; + Key next = index + 1 < recipes.size() ? Constants.RECIPE_NEXT_PAGE_AVAILABLE : Constants.RECIPE_NEXT_PAGE_BLOCK; + Key result = recipe.result().item().id(); + GuiLayout layout = new GuiLayout( + " ", + " ", + " ABC X ", + " ^ ", + " ", + " < = > " + ) + .addIngredient('X', GuiElement.constant(this.plugin.itemManager().createWrappedItem(result, player).count(recipe.result().count()), (e, c) -> { + c.cancel(); + if (MIDDLE_CLICK.contains(c.type()) && player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION) && c.itemOnCursor() == null) { + Item item = this.plugin.itemManager().createWrappedItem(result, player); + item.count(item.maxStackSize()); + c.setItemOnCursor(item); + return; + } + if (LEFT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } else if (canOpenNoRecipePage) { + openNoRecipePage(player, result, e.gui(), 0); + } + } else if (RIGHT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } + } + })) + .addIngredient('^', player.hasPermission(GET_ITEM_PERMISSION) ? GuiElement.constant(this.plugin.itemManager().createWrappedItem(Constants.RECIPE_GET_ITEM, player), (e, c) -> { + c.cancel(); + player.playSound(Constants.SOUND_PICK_ITEM); + if (LEFT_CLICK.contains(c.type())) { + player.giveItem(this.plugin.itemManager().createWrappedItem(result, player)); + } else if (RIGHT_CLICK.contains(c.type())) { + Item item = this.plugin.itemManager().createWrappedItem(result, player); + player.giveItem(item.count(item.maxStackSize())); + } + }) : GuiElement.EMPTY) + .addIngredient('=', GuiElement.constant(this.plugin.itemManager().getCustomItem(parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT) + .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.EMPTY))) + .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + (parentGui != null ? Constants.RECIPE_BACK : Constants.RECIPE_EXIT))), + ((element, click) -> { + click.cancel(); + player.playSound(Constants.SOUND_RETURN_PAGE, 0.25f, 1); + if (parentGui != null) { + parentGui.open(player); + } else { + player.closeInventory(); + } + })) + ) + .addIngredient('>', GuiElement.constant(this.plugin.itemManager() + .getCustomItem(next) + .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() + .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) + .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) + .build()))) + .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + next)), (e, c) -> { + c.cancel(); + if (index + 1 < recipes.size()) { + player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1); + openRecipePage(player, parentGui, recipes, index + 1, depth, canOpenNoRecipePage); + } + })) + .addIngredient('<', GuiElement.constant(this.plugin.itemManager() + .getCustomItem(previous) + .map(it -> it.buildItem(ItemBuildContext.of(player, ContextHolder.builder() + .withParameter(GuiParameters.CURRENT_PAGE, String.valueOf(index + 1)) + .withParameter(GuiParameters.MAX_PAGE, String.valueOf(recipes.size())) + .build()))) + .orElseThrow(() -> new GuiElementMissingException("Can't find gui element " + previous)), (e, c) -> { + c.cancel(); + if (index > 0) { + player.playSound(Constants.SOUND_CHANGE_PAGE, 0.25f, 1); + openRecipePage(player, parentGui, recipes, index - 1, depth, canOpenNoRecipePage); + } + })); + + + List> templates = new ArrayList<>(); + Optional.ofNullable(recipe.template()).ifPresent(it -> { + for (Holder in : it.items()) { + templates.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + } + }); + layout.addIngredient('A', templates.isEmpty() ? GuiElement.EMPTY : GuiElement.recipeIngredient(templates, (e, c) -> { + c.cancel(); + if (MIDDLE_CLICK.contains(c.type()) && player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION) && c.itemOnCursor() == null) { + Item item = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + item.count(item.maxStackSize()); + c.setItemOnCursor(item); + return; + } + if (LEFT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } else if (canOpenNoRecipePage) { + openNoRecipePage(player, e.item().id(), e.gui(), 0); + } + } else if (RIGHT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } + } + })); + + List> bases = new ArrayList<>(); + Optional.ofNullable(recipe.base()).ifPresent(it -> { + for (Holder in : it.items()) { + bases.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + } + }); + layout.addIngredient('B', bases.isEmpty() ? GuiElement.EMPTY : GuiElement.recipeIngredient(bases, (e, c) -> { + c.cancel(); + if (MIDDLE_CLICK.contains(c.type()) && player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION) && c.itemOnCursor() == null) { + Item item = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + item.count(item.maxStackSize()); + c.setItemOnCursor(item); + return; + } + if (LEFT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } else if (canOpenNoRecipePage) { + openNoRecipePage(player, e.item().id(), e.gui(), 0); + } + } else if (RIGHT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } + } + })); + + List> additions = new ArrayList<>(); + Optional.ofNullable(recipe.addition()).ifPresent(it -> { + for (Holder in : it.items()) { + additions.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + } + }); + layout.addIngredient('C', additions.isEmpty() ? GuiElement.EMPTY : GuiElement.recipeIngredient(additions, (e, c) -> { + c.cancel(); + if (MIDDLE_CLICK.contains(c.type()) && player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION) && c.itemOnCursor() == null) { + Item item = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + item.count(item.maxStackSize()); + c.setItemOnCursor(item); + return; + } + if (LEFT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } else if (canOpenNoRecipePage) { + openNoRecipePage(player, e.item().id(), e.gui(), 0); + } + } else if (RIGHT_CLICK.contains(c.type())) { + List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + if (inRecipes == recipes) return; + player.playSound(Constants.SOUND_CLICK_BUTTON); + if (!inRecipes.isEmpty()) { + openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); + } + } + })); + + BasicGui.builder() + .layout(layout) + .inventoryClickConsumer(c -> { + if (MOVE_TO_OTHER_INV.contains(c.type()) || DOUBLE_CLICK.contains(c.type())) { + c.cancel(); + } + }) + .build() + .title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_SMITHING_TRANSFORM_TITLE, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers())) + .refresh() + .open(player); } public void openStoneCuttingRecipePage(Player player, CustomStoneCuttingRecipe recipe, Gui parentGui, List> recipes, int index, int depth, boolean canOpenNoRecipePage) { 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 8f2a53152..a1c907c9d 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.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; import net.momirealms.craftengine.core.loot.condition.LootConditionFactory; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; @@ -43,6 +44,7 @@ public class BuiltInRegistries { public static final Registry FORMULA_FACTORY = createRegistry(Registries.FORMULA_FACTORY); public static final Registry PATH_MATCHER_FACTORY = createRegistry(Registries.PATH_MATCHER_FACTORY); public static final Registry RESOLUTION_FACTORY = createRegistry(Registries.RESOLUTION_FACTORY); + public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(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 5d8047bf9..3d766235f 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.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; import net.momirealms.craftengine.core.loot.condition.LootConditionFactory; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; @@ -44,4 +45,5 @@ public class Registries { public static final ResourceKey> FORMULA_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("formula_factory")); public static final ResourceKey> PATH_MATCHER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); public static final ResourceKey> RESOLUTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); + public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); } diff --git a/gradle.properties b/gradle.properties index fbc8cbd28..eb61f868c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.34 -config_version=14 +project_version=0.0.35 +config_version=15 lang_version=3 project_group=net.momirealms latest_minecraft_version=1.21.4 @@ -38,7 +38,7 @@ geantyref_version=1.3.16 zstd_version=1.5.6-9 commons_io_version=2.17.0 sparrow_nbt_version=0.3 -sparrow_util_version=0.22 +sparrow_util_version=0.29 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 18362b78b..c6f003026 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/server-mod/build.gradle.kts b/server-mod/build.gradle.kts index 8f3a35e5e..e2ca5fbe4 100644 --- a/server-mod/build.gradle.kts +++ b/server-mod/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java-library") - id("com.gradleup.shadow") version "9.0.0-beta6" - id("io.papermc.paperweight.userdev") version "2.0.0-beta.14" + id("com.gradleup.shadow") version "9.0.0-beta11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.16" } repositories { diff --git a/settings.gradle.kts b/settings.gradle.kts index 26b036286..02db6f8bf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,5 +9,9 @@ pluginManagement { plugins { kotlin("jvm") version "2.0.20" } + repositories { + gradlePluginPortal() + maven("https://repo.papermc.io/repository/maven-public/") + } }