From 492f0f87e062fb3fbc14455b3f6a61587ec5a8d2 Mon Sep 17 00:00:00 2001 From: rozarke Date: Sat, 30 May 2026 07:29:53 +0200 Subject: [PATCH 1/2] fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage --- build.gradle | 2 +- .../compat/emi/BlueprintCloningEmiRecipe.java | 103 ++++++++++++++ .../compat/emi/FletchingEmiRecipe.java | 37 +++++ .../compat/emi/ForgingEmiRecipe.java | 13 ++ .../compat/emi/OvergearedEmiPlugin.java | 42 ++++++ .../compat/emi/PotionFletchingEmiRecipe.java | 133 ++++++++++++++++++ 6 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java create mode 100644 src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java diff --git a/build.gradle b/build.gradle index 88151810..a5ea76ff 100644 --- a/build.gradle +++ b/build.gradle @@ -142,7 +142,7 @@ dependencies { } } implementation "maven.modrinth:create-aeronautics:1.1.3+mc1.21.1" - implementation "curse.maven:wooden-tools-are-dumb-736942:5695358" + compileOnly "curse.maven:wooden-tools-are-dumb-736942:5695358" implementation "curse.maven:selene-499980:7708176" runtimeOnly "curse.maven:mmmmmmmmmmmm-225738:7206981" /*modImplementation "curse.maven:biolith-852512:7074761" diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java new file mode 100644 index 00000000..f254d1e5 --- /dev/null +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java @@ -0,0 +1,103 @@ +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.recipe.VanillaEmiRecipeCategories; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.stirdrem.overgeared.BlueprintQuality; +import net.stirdrem.overgeared.OvergearedMod; +import net.stirdrem.overgeared.components.BlueprintData; +import net.stirdrem.overgeared.components.ModComponents; +import net.stirdrem.overgeared.item.ModItems; + +import java.util.List; + +/** + * EMI recipe display for Blueprint Cloning (crafting table). + * One entry per quality tier: shows [quality blueprint] + [empty blueprint] → [downgraded blueprint x2]. + */ +public class BlueprintCloningEmiRecipe implements EmiRecipe { + + private final ResourceLocation id; + private final List inputs; + private final List outputs; + + public BlueprintCloningEmiRecipe(BlueprintQuality quality) { + this.id = OvergearedMod.loc("blueprint_cloning/" + quality.getId()); + + // Input: blueprint at this quality tier + ItemStack inputStack = new ItemStack(ModItems.BLUEPRINT.get()); + BlueprintData inputData = BlueprintData.createDefault().withQuality(quality.getId()); + inputStack.set(ModComponents.BLUEPRINT_DATA, inputData); + + // Output: blueprint at the downgraded quality (x2). + BlueprintQuality outputQuality = BlueprintQuality.getPrevious(quality); + if (outputQuality == null || outputQuality == BlueprintQuality.NONE) outputQuality = quality; + + ItemStack outputStack = new ItemStack(ModItems.BLUEPRINT.get(), 2); + BlueprintData outputData = BlueprintData.createDefault().withQuality(outputQuality.getId()); + outputStack.set(ModComponents.BLUEPRINT_DATA, outputData); + + this.inputs = List.of( + EmiStack.of(inputStack), + EmiIngredient.of(Ingredient.of(ModItems.EMPTY_BLUEPRINT.get())) + ); + this.outputs = List.of(EmiStack.of(outputStack)); + } + + @Override + public EmiRecipeCategory getCategory() { + return VanillaEmiRecipeCategories.CRAFTING; + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public List getInputs() { + return inputs; + } + + @Override + public List getOutputs() { + return outputs; + } + + @Override + public int getDisplayWidth() { + return 116; + } + + @Override + public int getDisplayHeight() { + return 54; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + + widgets.addSlot(inputs.get(0), 0, 0); + widgets.addSlot(inputs.get(1), 18, 0); + widgets.addSlot(EmiStack.EMPTY, 36, 0); + widgets.addSlot(EmiStack.EMPTY, 0, 18); + widgets.addSlot(EmiStack.EMPTY, 18, 18); + widgets.addSlot(EmiStack.EMPTY, 36, 18); + widgets.addSlot(EmiStack.EMPTY, 0, 36); + widgets.addSlot(EmiStack.EMPTY, 18, 36); + widgets.addSlot(EmiStack.EMPTY, 36, 36); + + // Arrow + widgets.addTexture(EmiTexture.EMPTY_ARROW, 60, 18); + + // Output + widgets.addSlot(outputs.getFirst(), 90, 14).large(true).recipeContext(this); + } +} diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java index 0b539a41..0fe47033 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java @@ -77,6 +77,7 @@ public void addWidgets(WidgetHolder widgets) { // Match in-game GUI diagonal layout int offsetX = 4; int offsetY = 4; +<<<<<<< HEAD // Tip slot (top-right of diagonal) int tipX = offsetX + 36; @@ -94,6 +95,42 @@ public void addWidgets(WidgetHolder widgets) { widgets.addSlot(EmiIngredient.of(recipe.getFeather()), featherX, featherY); // Arrow +======= + + if (variant == Variant.BASE) { + // Tip slot (top-right of diagonal) + int tipX = offsetX + 36; + int tipY = offsetY; + widgets.addSlot(EmiIngredient.of(recipe.getTip()), tipX, tipY); + + // Shaft slot (middle-left) + int shaftX = offsetX + 18; + int shaftY = offsetY + SLOT_SIZE; + widgets.addSlot(EmiIngredient.of(recipe.getShaft()), shaftX, shaftY); + + // Feather slot (bottom-left) + int featherX = offsetX; + int featherY = offsetY + SLOT_SIZE * 2; + widgets.addSlot(EmiIngredient.of(recipe.getFeather()), featherX, featherY); + } else { + EmiIngredient arrow = EmiStack.of(recipe.getDefaultResult().copyWithCount(1)); + EmiIngredient potion = variant == Variant.TIPPED + ? (recipe.hasPotion() ? EmiIngredient.of(recipe.getPotion()) + : EmiStack.of(PotionContents.createItemStack(Items.POTION, Potions.NIGHT_VISION))) + : (recipe.hasPotion() ? EmiIngredient.of(recipe.getPotion()) + : EmiStack.of(PotionContents.createItemStack(Items.LINGERING_POTION, Potions.NIGHT_VISION))); + + int shaftX = offsetX + 18; + int shaftY = offsetY + SLOT_SIZE; + widgets.addSlot(arrow, shaftX, shaftY); + + int potionX = offsetX + 36; + int potionY = offsetY + SLOT_SIZE * 2; + widgets.addSlot(potion, potionX, potionY); + } + + // Arrow +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) int arrowX = offsetX + 54; int arrowY = offsetY + SLOT_SIZE; widgets.addTexture(EmiTexture.EMPTY_ARROW, arrowX, arrowY); diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java index 3f831926..0c55765a 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java @@ -52,6 +52,19 @@ public ForgingEmiRecipe(RecipeHolder holder) { // Create blueprint stacks for recipes that support blueprints this.blueprintStacks = createBlueprintStacks(); +<<<<<<< HEAD +======= + + + // surfaces forging recipes that accept one + List inputList = new ArrayList<>(recipe.getIngredients().stream() + .map(EmiIngredient::of) + .toList()); + if (!blueprintStacks.isEmpty()) { + inputList.add(EmiIngredient.of(Ingredient.of(ModItems.BLUEPRINT.get()))); + } + this.inputs = inputList; +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) } /** diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java b/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java index 58a1a01e..28acbae0 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java @@ -13,11 +13,16 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +<<<<<<< HEAD +======= +import net.minecraft.world.item.alchemy.Potion; +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.material.Fluids; import net.neoforged.neoforge.common.Tags; +import net.stirdrem.overgeared.BlueprintQuality; import net.stirdrem.overgeared.OvergearedMod; import net.stirdrem.overgeared.block.ModBlocks; import net.stirdrem.overgeared.config.ServerConfig; @@ -205,6 +210,43 @@ public void register(EmiRegistry registry) { registry.addRecipe(new FletchingEmiRecipe(holder)); } +<<<<<<< HEAD +======= + // Register per-potion tipped/lingering entries for each arrow type. + // Vanilla arrow: arrow → tipped_arrow / lingering_arrow (always shown). + // Upgrade arrows (iron/steel/diamond): only when UPGRADE_ARROW_POTION_TOGGLE is enabled. + List arrowItems = new ArrayList<>(); + arrowItems.add(Items.ARROW); // vanilla always included + if (ServerConfig.UPGRADE_ARROW_POTION_TOGGLE.get()) { + arrowItems.add(ModItems.IRON_UPGRADE_ARROW.get()); + arrowItems.add(ModItems.STEEL_UPGRADE_ARROW.get()); + arrowItems.add(ModItems.DIAMOND_UPGRADE_ARROW.get()); + } + for (Item arrowItem : arrowItems) { + for (Holder potionHolder : BuiltInRegistries.POTION.holders().toList()) { + if (potionHolder.value().getEffects().isEmpty()) continue; + ResourceLocation potionKey = BuiltInRegistries.POTION.getKey(potionHolder.value()); + if (potionKey == null) continue; + registry.addRecipe(new PotionFletchingEmiRecipe( + arrowItem, potionHolder, potionKey, PotionFletchingEmiRecipe.Variant.TIPPED)); + registry.addRecipe(new PotionFletchingEmiRecipe( + arrowItem, potionHolder, potionKey, PotionFletchingEmiRecipe.Variant.LINGERING)); + } + } + + // Register Blueprint Cloning — one entry per quality tier (crafting table) + for (BlueprintQuality quality : new BlueprintQuality[]{ + BlueprintQuality.POOR, BlueprintQuality.WELL, BlueprintQuality.EXPERT, + BlueprintQuality.PERFECT, BlueprintQuality.MASTER}) { + registry.addRecipe(new BlueprintCloningEmiRecipe(quality)); + } + + // Drafting Table explanation + registry.addCategory(DRAFTING_TABLE_CATEGORY); + registry.addWorkstation(DRAFTING_TABLE_CATEGORY, DRAFTING_TABLE_WORKSTATION); + registry.addRecipe(new DraftingTableEmiRecipe()); + +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) registry.addCategory(COOLING_CATEGORY); registry.addWorkstation(COOLING_CATEGORY, COOLING_WORKSTATION); diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java new file mode 100644 index 00000000..91892184 --- /dev/null +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java @@ -0,0 +1,133 @@ +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.Comparison; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.core.Holder; +import net.minecraft.core.component.DataComponents; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.PotionContents; +import net.stirdrem.overgeared.OvergearedMod; +import net.stirdrem.overgeared.components.ModComponents; +import net.stirdrem.overgeared.item.ModItems; + +import java.util.List; + +/** + * EMI recipe entry for arrow and potion conversion in the fletching table (Path 1). + * - Arrow in the TIP slot, shaft and feather empty, potion in potion slot + * - One entry per: arrow type × potion × variant (TIPPED / LINGERING) + * - Includes vanilla arrow (→ tipped_arrow / lingering_arrow) + * - Includes upgrade arrows (iron/steel/diamond → same item + POTION_CONTENTS) + */ +public class PotionFletchingEmiRecipe implements EmiRecipe { + + public enum Variant { TIPPED, LINGERING } + + private static final int SLOT_SIZE = 18; + + private final ResourceLocation id; + private final Variant variant; + private final List inputs; + private final List outputs; + + public PotionFletchingEmiRecipe(Item arrowItem, Holder potion, + ResourceLocation potionKey, Variant variant) { + String arrowPath = arrowItem.builtInRegistryHolder().key().location().getPath(); + this.id = OvergearedMod.loc("fletching/" + variant.name().toLowerCase() + + "_conv/" + arrowPath + "/" + potionKey.getPath()); + this.variant = variant; + + // Input: 1x base arrow (goes in tip slot) + ItemStack arrowInput = new ItemStack(arrowItem, 1); + + // Input: specific potion + Item potionItem = variant == Variant.TIPPED ? Items.POTION : Items.LINGERING_POTION; + ItemStack potionStack = PotionContents.createItemStack(potionItem, potion); + + this.inputs = List.of(EmiStack.of(arrowInput), EmiStack.of(potionStack)); + + // Output depends on arrow type and variant + PotionContents contents = potionStack.get(DataComponents.POTION_CONTENTS); + ItemStack output; + + if (arrowItem == Items.ARROW) { + // Vanilla arrow → tipped_arrow or lingering_arrow (different items) + if (variant == Variant.TIPPED) { + output = new ItemStack(Items.TIPPED_ARROW, 1); + } else { + output = new ItemStack(ModItems.LINGERING_ARROW.get(), 1); + } + } else { + // Upgrade arrow → same item with potion contents + output = new ItemStack(arrowItem, 1); + if (variant == Variant.LINGERING) { + output.set(ModComponents.LINGERING_STATUS, true); + } + } + if (contents != null) output.set(DataComponents.POTION_CONTENTS, contents); + + // only shows THIS recipe, not all tipped/lingering recipes for this arrow. + EmiStack outputStack = EmiStack.of(output).comparison(Comparison.compareComponents()); + this.outputs = List.of(outputStack); + } + + @Override + public EmiRecipeCategory getCategory() { + return OvergearedEmiPlugin.FLETCHING_CATEGORY; + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public List getInputs() { + return inputs; + } + + @Override + public List getOutputs() { + return outputs; + } + + @Override + public int getDisplayWidth() { + return 120; + } + + @Override + public int getDisplayHeight() { + return 60; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + int offsetX = 4; + int offsetY = 4; + + // Arrow in shaft slot (middle) for aesthetics, tip and feather empty + widgets.addSlot(EmiStack.EMPTY, offsetX + 36, offsetY); + widgets.addSlot(inputs.get(0), offsetX + 18, offsetY + SLOT_SIZE); + widgets.addSlot(EmiStack.EMPTY, offsetX, offsetY + SLOT_SIZE * 2); + + // Potion in potion slot (bottom-right) + widgets.addSlot(inputs.get(1), offsetX + 36, offsetY + SLOT_SIZE * 2); + + // Arrow + widgets.addTexture(EmiTexture.EMPTY_ARROW, offsetX + 54, offsetY + SLOT_SIZE); + + // Output + widgets.addSlot(outputs.getFirst(), offsetX + 82, offsetY + SLOT_SIZE - 4) + .large(true).recipeContext(this); + } +} From 9192daee314d612a56fcc0c62e5cf6f71adab63d Mon Sep 17 00:00:00 2001 From: rozarke Date: Sat, 30 May 2026 08:27:13 +0200 Subject: [PATCH 2/2] Add EMI compat: BlueprintCloning, PotionFletching, DraftingTable recipes; update Fletching, Forging, Plugin, en_us.json --- .../compat/emi/BlueprintCloningEmiRecipe.java | 206 +++--- .../compat/emi/DraftingTableEmiRecipe.java | 102 +++ .../compat/emi/FletchingEmiRecipe.java | 286 ++++---- .../compat/emi/ForgingEmiRecipe.java | 436 ++++++------ .../compat/emi/OvergearedEmiPlugin.java | 662 +++++++++--------- .../compat/emi/PotionFletchingEmiRecipe.java | 266 +++---- .../assets/overgeared/lang/en_us.json | 2 + 7 files changed, 1032 insertions(+), 928 deletions(-) create mode 100644 src/main/java/net/stirdrem/overgeared/compat/emi/DraftingTableEmiRecipe.java diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java index f254d1e5..a12a51ee 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/BlueprintCloningEmiRecipe.java @@ -1,103 +1,103 @@ -package net.stirdrem.overgeared.compat.emi; - -import dev.emi.emi.api.recipe.EmiRecipe; -import dev.emi.emi.api.recipe.EmiRecipeCategory; -import dev.emi.emi.api.recipe.VanillaEmiRecipeCategories; -import dev.emi.emi.api.render.EmiTexture; -import dev.emi.emi.api.stack.EmiIngredient; -import dev.emi.emi.api.stack.EmiStack; -import dev.emi.emi.api.widget.WidgetHolder; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; -import net.stirdrem.overgeared.BlueprintQuality; -import net.stirdrem.overgeared.OvergearedMod; -import net.stirdrem.overgeared.components.BlueprintData; -import net.stirdrem.overgeared.components.ModComponents; -import net.stirdrem.overgeared.item.ModItems; - -import java.util.List; - -/** - * EMI recipe display for Blueprint Cloning (crafting table). - * One entry per quality tier: shows [quality blueprint] + [empty blueprint] → [downgraded blueprint x2]. - */ -public class BlueprintCloningEmiRecipe implements EmiRecipe { - - private final ResourceLocation id; - private final List inputs; - private final List outputs; - - public BlueprintCloningEmiRecipe(BlueprintQuality quality) { - this.id = OvergearedMod.loc("blueprint_cloning/" + quality.getId()); - - // Input: blueprint at this quality tier - ItemStack inputStack = new ItemStack(ModItems.BLUEPRINT.get()); - BlueprintData inputData = BlueprintData.createDefault().withQuality(quality.getId()); - inputStack.set(ModComponents.BLUEPRINT_DATA, inputData); - - // Output: blueprint at the downgraded quality (x2). - BlueprintQuality outputQuality = BlueprintQuality.getPrevious(quality); - if (outputQuality == null || outputQuality == BlueprintQuality.NONE) outputQuality = quality; - - ItemStack outputStack = new ItemStack(ModItems.BLUEPRINT.get(), 2); - BlueprintData outputData = BlueprintData.createDefault().withQuality(outputQuality.getId()); - outputStack.set(ModComponents.BLUEPRINT_DATA, outputData); - - this.inputs = List.of( - EmiStack.of(inputStack), - EmiIngredient.of(Ingredient.of(ModItems.EMPTY_BLUEPRINT.get())) - ); - this.outputs = List.of(EmiStack.of(outputStack)); - } - - @Override - public EmiRecipeCategory getCategory() { - return VanillaEmiRecipeCategories.CRAFTING; - } - - @Override - public ResourceLocation getId() { - return id; - } - - @Override - public List getInputs() { - return inputs; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public int getDisplayWidth() { - return 116; - } - - @Override - public int getDisplayHeight() { - return 54; - } - - @Override - public void addWidgets(WidgetHolder widgets) { - - widgets.addSlot(inputs.get(0), 0, 0); - widgets.addSlot(inputs.get(1), 18, 0); - widgets.addSlot(EmiStack.EMPTY, 36, 0); - widgets.addSlot(EmiStack.EMPTY, 0, 18); - widgets.addSlot(EmiStack.EMPTY, 18, 18); - widgets.addSlot(EmiStack.EMPTY, 36, 18); - widgets.addSlot(EmiStack.EMPTY, 0, 36); - widgets.addSlot(EmiStack.EMPTY, 18, 36); - widgets.addSlot(EmiStack.EMPTY, 36, 36); - - // Arrow - widgets.addTexture(EmiTexture.EMPTY_ARROW, 60, 18); - - // Output - widgets.addSlot(outputs.getFirst(), 90, 14).large(true).recipeContext(this); - } -} +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.recipe.VanillaEmiRecipeCategories; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.stirdrem.overgeared.BlueprintQuality; +import net.stirdrem.overgeared.OvergearedMod; +import net.stirdrem.overgeared.components.BlueprintData; +import net.stirdrem.overgeared.components.ModComponents; +import net.stirdrem.overgeared.item.ModItems; + +import java.util.List; + +/** + * EMI recipe display for Blueprint Cloning (crafting table). + * One entry per quality tier: shows [quality blueprint] + [empty blueprint] → [downgraded blueprint x2]. + */ +public class BlueprintCloningEmiRecipe implements EmiRecipe { + + private final ResourceLocation id; + private final List inputs; + private final List outputs; + + public BlueprintCloningEmiRecipe(BlueprintQuality quality) { + this.id = OvergearedMod.loc("blueprint_cloning/" + quality.getId()); + + // Input: blueprint at this quality tier + ItemStack inputStack = new ItemStack(ModItems.BLUEPRINT.get()); + BlueprintData inputData = BlueprintData.createDefault().withQuality(quality.getId()); + inputStack.set(ModComponents.BLUEPRINT_DATA, inputData); + + // Output: blueprint at the downgraded quality (x2). + BlueprintQuality outputQuality = BlueprintQuality.getPrevious(quality); + if (outputQuality == null || outputQuality == BlueprintQuality.NONE) outputQuality = quality; + + ItemStack outputStack = new ItemStack(ModItems.BLUEPRINT.get(), 2); + BlueprintData outputData = BlueprintData.createDefault().withQuality(outputQuality.getId()); + outputStack.set(ModComponents.BLUEPRINT_DATA, outputData); + + this.inputs = List.of( + EmiStack.of(inputStack), + EmiIngredient.of(Ingredient.of(ModItems.EMPTY_BLUEPRINT.get())) + ); + this.outputs = List.of(EmiStack.of(outputStack)); + } + + @Override + public EmiRecipeCategory getCategory() { + return VanillaEmiRecipeCategories.CRAFTING; + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public List getInputs() { + return inputs; + } + + @Override + public List getOutputs() { + return outputs; + } + + @Override + public int getDisplayWidth() { + return 116; + } + + @Override + public int getDisplayHeight() { + return 54; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + + widgets.addSlot(inputs.get(0), 0, 0); + widgets.addSlot(inputs.get(1), 18, 0); + widgets.addSlot(EmiStack.EMPTY, 36, 0); + widgets.addSlot(EmiStack.EMPTY, 0, 18); + widgets.addSlot(EmiStack.EMPTY, 18, 18); + widgets.addSlot(EmiStack.EMPTY, 36, 18); + widgets.addSlot(EmiStack.EMPTY, 0, 36); + widgets.addSlot(EmiStack.EMPTY, 18, 36); + widgets.addSlot(EmiStack.EMPTY, 36, 36); + + // Arrow + widgets.addTexture(EmiTexture.EMPTY_ARROW, 60, 18); + + // Output + widgets.addSlot(outputs.getFirst(), 90, 14).large(true).recipeContext(this); + } +} diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/DraftingTableEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/DraftingTableEmiRecipe.java new file mode 100644 index 00000000..81c1f548 --- /dev/null +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/DraftingTableEmiRecipe.java @@ -0,0 +1,102 @@ +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.crafting.Ingredient; +import net.stirdrem.overgeared.OvergearedMod; +import net.stirdrem.overgeared.block.ModBlocks; +import net.stirdrem.overgeared.item.ModItems; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class DraftingTableEmiRecipe implements EmiRecipe { + + private final EmiIngredient input; + private final EmiStack output; + + public DraftingTableEmiRecipe() { + this.input = EmiIngredient.of(Ingredient.of(ModItems.EMPTY_BLUEPRINT.get())); + this.output = EmiStack.of(ModItems.BLUEPRINT.get()); + } + + @Override + public EmiRecipeCategory getCategory() { + return OvergearedEmiPlugin.DRAFTING_TABLE_CATEGORY; + } + + @Override + public @Nullable ResourceLocation getId() { + return OvergearedMod.loc("explanation/drafting_table"); + } + + @Override + public List getInputs() { + return List.of(input); + } + + @Override + public List getOutputs() { + return List.of(output); + } + + @Override + public int getDisplayWidth() { + return 150; + } + + @Override + public int getDisplayHeight() { + return 150; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + int startY = 10; + + int slotSize = 18; + int arrowWidth = 24; + int gap = 6; + + int totalWidth = slotSize + gap + arrowWidth + gap + slotSize; + int startX = (getDisplayWidth() - totalWidth) / 2; + + int inputX = startX; + int arrowX = inputX + slotSize + gap; + int outputX = arrowX + arrowWidth + gap; + + // Input slot (empty blueprint) + widgets.addSlot(input, inputX, startY).drawBack(true); + + // Arrow + widgets.addTexture(EmiTexture.EMPTY_ARROW, arrowX, startY + 1); + + // Output slot (blueprint) + widgets.addSlot(output, outputX, startY).drawBack(true).recipeContext(this); + + // Explanation text + int textWidth = getDisplayWidth() - 20; + int textX = 10; + int textY = startY + 30; + + Component text = Component.translatable("jei.overgeared.drafting_table.description"); + + Font font = Minecraft.getInstance().font; + List lines = font.split(text, textWidth); + + for (FormattedCharSequence line : lines) { + widgets.addText(line, textX, textY, ChatFormatting.DARK_GRAY.getColor(), false); + textY += 10; + } + } +} diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java index 0fe47033..881b5eb2 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/FletchingEmiRecipe.java @@ -1,143 +1,143 @@ -package net.stirdrem.overgeared.compat.emi; - -import dev.emi.emi.api.recipe.EmiRecipe; -import dev.emi.emi.api.recipe.EmiRecipeCategory; -import dev.emi.emi.api.render.EmiTexture; -import dev.emi.emi.api.stack.EmiIngredient; -import dev.emi.emi.api.stack.EmiStack; -import dev.emi.emi.api.widget.WidgetHolder; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.crafting.RecipeHolder; -import net.stirdrem.overgeared.recipe.FletchingRecipe; - -import java.util.ArrayList; -import java.util.List; - -/** - * EMI recipe display for Fletching recipes. - * Shows the diagonal slot layout matching the in-game GUI. - * Displays the base arrow recipe - potion variants are applied at runtime with any potion. - */ -public class FletchingEmiRecipe implements EmiRecipe { - - private static final int SLOT_SIZE = 18; - - private final ResourceLocation id; - private final FletchingRecipe recipe; - private final List inputs; - private final List outputs; - - public FletchingEmiRecipe(RecipeHolder holder) { - this.id = holder.id(); - this.recipe = holder.value(); - - // Build inputs list: tip, shaft, feather - List inputList = new ArrayList<>(); - inputList.add(EmiIngredient.of(recipe.getTip())); - inputList.add(EmiIngredient.of(recipe.getShaft())); - inputList.add(EmiIngredient.of(recipe.getFeather())); - this.inputs = inputList; - - // Just show the default result - potion variants are runtime behavior - this.outputs = List.of(EmiStack.of(recipe.getDefaultResult())); - } - - @Override - public EmiRecipeCategory getCategory() { - return OvergearedEmiPlugin.FLETCHING_CATEGORY; - } - - @Override - public ResourceLocation getId() { - return id; - } - - @Override - public List getInputs() { - return inputs; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public int getDisplayWidth() { - return 120; - } - - @Override - public int getDisplayHeight() { - return 60; - } - - @Override - public void addWidgets(WidgetHolder widgets) { - // Match in-game GUI diagonal layout - int offsetX = 4; - int offsetY = 4; -<<<<<<< HEAD - - // Tip slot (top-right of diagonal) - int tipX = offsetX + 36; - int tipY = offsetY; - widgets.addSlot(EmiIngredient.of(recipe.getTip()), tipX, tipY); - - // Shaft slot (middle-left) - int shaftX = offsetX + 18; - int shaftY = offsetY + SLOT_SIZE; - widgets.addSlot(EmiIngredient.of(recipe.getShaft()), shaftX, shaftY); - - // Feather slot (bottom-left) - int featherX = offsetX; - int featherY = offsetY + SLOT_SIZE * 2; - widgets.addSlot(EmiIngredient.of(recipe.getFeather()), featherX, featherY); - - // Arrow -======= - - if (variant == Variant.BASE) { - // Tip slot (top-right of diagonal) - int tipX = offsetX + 36; - int tipY = offsetY; - widgets.addSlot(EmiIngredient.of(recipe.getTip()), tipX, tipY); - - // Shaft slot (middle-left) - int shaftX = offsetX + 18; - int shaftY = offsetY + SLOT_SIZE; - widgets.addSlot(EmiIngredient.of(recipe.getShaft()), shaftX, shaftY); - - // Feather slot (bottom-left) - int featherX = offsetX; - int featherY = offsetY + SLOT_SIZE * 2; - widgets.addSlot(EmiIngredient.of(recipe.getFeather()), featherX, featherY); - } else { - EmiIngredient arrow = EmiStack.of(recipe.getDefaultResult().copyWithCount(1)); - EmiIngredient potion = variant == Variant.TIPPED - ? (recipe.hasPotion() ? EmiIngredient.of(recipe.getPotion()) - : EmiStack.of(PotionContents.createItemStack(Items.POTION, Potions.NIGHT_VISION))) - : (recipe.hasPotion() ? EmiIngredient.of(recipe.getPotion()) - : EmiStack.of(PotionContents.createItemStack(Items.LINGERING_POTION, Potions.NIGHT_VISION))); - - int shaftX = offsetX + 18; - int shaftY = offsetY + SLOT_SIZE; - widgets.addSlot(arrow, shaftX, shaftY); - - int potionX = offsetX + 36; - int potionY = offsetY + SLOT_SIZE * 2; - widgets.addSlot(potion, potionX, potionY); - } - - // Arrow ->>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) - int arrowX = offsetX + 54; - int arrowY = offsetY + SLOT_SIZE; - widgets.addTexture(EmiTexture.EMPTY_ARROW, arrowX, arrowY); - - // Output - just the base result - int outputX = arrowX + 28; - int outputY = offsetY + SLOT_SIZE - 4; - widgets.addSlot(outputs.getFirst(), outputX, outputY).large(true).recipeContext(this); - } -} +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.stirdrem.overgeared.recipe.FletchingRecipe; + +import java.util.ArrayList; +import java.util.List; + +/** + * EMI recipe display for Fletching recipes. + * Shows the diagonal slot layout matching the in-game GUI. + * Displays the base arrow recipe - potion variants are applied at runtime with any potion. + */ +public class FletchingEmiRecipe implements EmiRecipe { + + private static final int SLOT_SIZE = 18; + + private final ResourceLocation id; + private final FletchingRecipe recipe; + private final List inputs; + private final List outputs; + + public FletchingEmiRecipe(RecipeHolder holder) { + this.id = holder.id(); + this.recipe = holder.value(); + + // Build inputs list: tip, shaft, feather + List inputList = new ArrayList<>(); + inputList.add(EmiIngredient.of(recipe.getTip())); + inputList.add(EmiIngredient.of(recipe.getShaft())); + inputList.add(EmiIngredient.of(recipe.getFeather())); + this.inputs = inputList; + + // Just show the default result - potion variants are runtime behavior + this.outputs = List.of(EmiStack.of(recipe.getDefaultResult())); + } + + @Override + public EmiRecipeCategory getCategory() { + return OvergearedEmiPlugin.FLETCHING_CATEGORY; + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public List getInputs() { + return inputs; + } + + @Override + public List getOutputs() { + return outputs; + } + + @Override + public int getDisplayWidth() { + return 120; + } + + @Override + public int getDisplayHeight() { + return 60; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + // Match in-game GUI diagonal layout + int offsetX = 4; + int offsetY = 4; +<<<<<<< HEAD + + // Tip slot (top-right of diagonal) + int tipX = offsetX + 36; + int tipY = offsetY; + widgets.addSlot(EmiIngredient.of(recipe.getTip()), tipX, tipY); + + // Shaft slot (middle-left) + int shaftX = offsetX + 18; + int shaftY = offsetY + SLOT_SIZE; + widgets.addSlot(EmiIngredient.of(recipe.getShaft()), shaftX, shaftY); + + // Feather slot (bottom-left) + int featherX = offsetX; + int featherY = offsetY + SLOT_SIZE * 2; + widgets.addSlot(EmiIngredient.of(recipe.getFeather()), featherX, featherY); + + // Arrow +======= + + if (variant == Variant.BASE) { + // Tip slot (top-right of diagonal) + int tipX = offsetX + 36; + int tipY = offsetY; + widgets.addSlot(EmiIngredient.of(recipe.getTip()), tipX, tipY); + + // Shaft slot (middle-left) + int shaftX = offsetX + 18; + int shaftY = offsetY + SLOT_SIZE; + widgets.addSlot(EmiIngredient.of(recipe.getShaft()), shaftX, shaftY); + + // Feather slot (bottom-left) + int featherX = offsetX; + int featherY = offsetY + SLOT_SIZE * 2; + widgets.addSlot(EmiIngredient.of(recipe.getFeather()), featherX, featherY); + } else { + EmiIngredient arrow = EmiStack.of(recipe.getDefaultResult().copyWithCount(1)); + EmiIngredient potion = variant == Variant.TIPPED + ? (recipe.hasPotion() ? EmiIngredient.of(recipe.getPotion()) + : EmiStack.of(PotionContents.createItemStack(Items.POTION, Potions.NIGHT_VISION))) + : (recipe.hasPotion() ? EmiIngredient.of(recipe.getPotion()) + : EmiStack.of(PotionContents.createItemStack(Items.LINGERING_POTION, Potions.NIGHT_VISION))); + + int shaftX = offsetX + 18; + int shaftY = offsetY + SLOT_SIZE; + widgets.addSlot(arrow, shaftX, shaftY); + + int potionX = offsetX + 36; + int potionY = offsetY + SLOT_SIZE * 2; + widgets.addSlot(potion, potionX, potionY); + } + + // Arrow +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) + int arrowX = offsetX + 54; + int arrowY = offsetY + SLOT_SIZE; + widgets.addTexture(EmiTexture.EMPTY_ARROW, arrowX, arrowY); + + // Output - just the base result + int outputX = arrowX + 28; + int outputY = offsetY + SLOT_SIZE - 4; + widgets.addSlot(outputs.getFirst(), outputX, outputY).large(true).recipeContext(this); + } +} diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java index 0c55765a..f437ef7f 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/ForgingEmiRecipe.java @@ -1,218 +1,218 @@ -package net.stirdrem.overgeared.compat.emi; - -import dev.emi.emi.api.recipe.EmiRecipe; -import dev.emi.emi.api.recipe.EmiRecipeCategory; -import dev.emi.emi.api.render.EmiTexture; -import dev.emi.emi.api.stack.EmiIngredient; -import dev.emi.emi.api.stack.EmiStack; -import dev.emi.emi.api.widget.WidgetHolder; -import net.minecraft.core.NonNullList; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.RecipeHolder; -import net.stirdrem.overgeared.AnvilTier; -import net.stirdrem.overgeared.components.BlueprintData; -import net.stirdrem.overgeared.components.ModComponents; -import net.stirdrem.overgeared.item.ModItems; -import net.stirdrem.overgeared.recipe.ForgingRecipe; -import net.stirdrem.overgeared.util.ModTags; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - -public class ForgingEmiRecipe implements EmiRecipe { - private static final int DISPLAY_WIDTH = 150; - private static final int DISPLAY_HEIGHT = 66; - private static final int X_OFFSET = 8; // Offset to center the recipe - - private final ResourceLocation id; - private final ForgingRecipe recipe; - private final List inputs; - private final List outputs; - private final List outputFailure; - private final List blueprintStacks; - - public ForgingEmiRecipe(RecipeHolder holder) { - this.id = holder.id(); - this.recipe = holder.value(); - - // Convert ingredients to EMI format - this.inputs = recipe.getIngredients().stream() - .map(EmiIngredient::of) - .toList(); - - this.outputs = List.of(EmiStack.of(recipe.getResultItem(null))); - ItemStack failureStack = recipe.getFailedResultItem(null).copy(); - failureStack.set(ModComponents.FAILED_RESULT, true); - this.outputFailure = List.of(EmiStack.of(failureStack)); - - // Create blueprint stacks for recipes that support blueprints - this.blueprintStacks = createBlueprintStacks(); -<<<<<<< HEAD -======= - - - // surfaces forging recipes that accept one - List inputList = new ArrayList<>(recipe.getIngredients().stream() - .map(EmiIngredient::of) - .toList()); - if (!blueprintStacks.isEmpty()) { - inputList.add(EmiIngredient.of(Ingredient.of(ModItems.BLUEPRINT.get()))); - } - this.inputs = inputList; ->>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) - } - - /** - * Create blueprint ItemStacks for this recipe's valid blueprint types. - */ - private List createBlueprintStacks() { - Set types = recipe.getBlueprintTypes(); - if (types.isEmpty()) { - return List.of(); - } - - List stacks = new ArrayList<>(); - for (String type : types) { - ItemStack stack = new ItemStack(ModItems.BLUEPRINT.get()); - // Use BlueprintData with builder pattern - BlueprintData data = BlueprintData.createDefault() - .withToolType(type); - stack.set(ModComponents.BLUEPRINT_DATA, data); - stack.set(ModComponents.BLUEPRINT_REQUIRED, recipe.requiresBlueprint()); - stacks.add(EmiStack.of(stack)); - } - return stacks; - } - - - @Override - public EmiRecipeCategory getCategory() { - return OvergearedEmiPlugin.FORGING_CATEGORY; - } - - @Override - public ResourceLocation getId() { - return id; - } - - @Override - public List getInputs() { - return inputs; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public int getDisplayWidth() { - return DISPLAY_WIDTH; - } - - @Override - public int getDisplayHeight() { - return DISPLAY_HEIGHT; - } - - @Override - public void addWidgets(WidgetHolder widgets) { - // Blueprint slot on the left - int blueprintX = X_OFFSET; - int blueprintY = 24; - if (!blueprintStacks.isEmpty()) { - // Show blueprint variants cycling through - widgets.addSlot(EmiIngredient.of(blueprintStacks), blueprintX, blueprintY); - } else { - widgets.addSlot(EmiStack.EMPTY, blueprintX, blueprintY); - } - - // 3x3 crafting grid - int gridStartX = X_OFFSET + 24; - int gridStartY = 6; - int slotSize = 18; - - int recipeWidth = recipe.width; - int recipeHeight = recipe.height; - - NonNullList forgingIngredients = - recipe.getForgingIngredients(); - - // Create all 9 slots of the 3x3 grid - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - int x = gridStartX + col * slotSize; - int y = gridStartY + row * slotSize; - - int recipeIndex = row * recipeWidth + col; - - if (col < recipeWidth && row < recipeHeight && recipeIndex < forgingIngredients.size()) { - - ForgingRecipe.ForgingIngredient forgingIngredient = - forgingIngredients.get(recipeIndex); - - Ingredient ingredient = forgingIngredient.ingredient(); - - EmiIngredient emiIngredient; - - if (forgingIngredient.requiresHeated() && !containsHeatedTaggedItem(ingredient)) { - List stacks = Arrays.stream(ingredient.getItems()) - .map(stack -> { - ItemStack copy = stack.copy(); - copy.set(ModComponents.HEATED_COMPONENT, true); - return EmiStack.of(copy); - }) - .toList(); - - emiIngredient = EmiIngredient.of(stacks); - } else { - emiIngredient = EmiIngredient.of(ingredient); - } - - widgets.addSlot(emiIngredient, x, y); - } else { - widgets.addSlot(EmiStack.EMPTY, x, y); - } - } - } - - - // Arrow texture - widgets.addTexture(EmiTexture.EMPTY_ARROW, X_OFFSET + 82, 24); - - // Output slot - int outputX = X_OFFSET + 110; - int outputY = 20; - if (outputFailure.getFirst().isEmpty()) - widgets.addSlot(outputs.getFirst(), outputX, outputY).large(true).recipeContext(this); - else { - widgets.addSlot(outputs.getFirst(), outputX, outputY + 4 - 9).large(false).recipeContext(this); - widgets.addSlot(outputFailure.getFirst(), outputX, outputY + 4 + 9).large(false).recipeContext(this); - } - // Draw "Hits: X" text (top right, above arrow) - String hitsText = Component.translatable("tooltip.overgeared.recipe.hits", recipe.getRemainingHits()).getString(); - widgets.addText(Component.literal(hitsText), X_OFFSET + 82, 6, 0xFF808080, false); - - // Draw "Tier: X" text (bottom, below grid) - String tierRaw = recipe.getAnvilTier(); - AnvilTier tierEnum = AnvilTier.fromDisplayName(tierRaw); - Component tierText = Component.translatable("tooltip.overgeared.recipe.tier") - .append(Component.literal(" ")) - .append(Component.translatable(tierEnum.getLang())); - widgets.addText(tierText, X_OFFSET + 82, 54, 0xFF808080, false); - } - - private static boolean containsHeatedTaggedItem(Ingredient ingredient) { - for (ItemStack stack : ingredient.getItems()) { - if (stack.is(ModTags.Items.HEATED_METALS)) { - return true; - } - } - return false; - } -} +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.stirdrem.overgeared.AnvilTier; +import net.stirdrem.overgeared.components.BlueprintData; +import net.stirdrem.overgeared.components.ModComponents; +import net.stirdrem.overgeared.item.ModItems; +import net.stirdrem.overgeared.recipe.ForgingRecipe; +import net.stirdrem.overgeared.util.ModTags; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +public class ForgingEmiRecipe implements EmiRecipe { + private static final int DISPLAY_WIDTH = 150; + private static final int DISPLAY_HEIGHT = 66; + private static final int X_OFFSET = 8; // Offset to center the recipe + + private final ResourceLocation id; + private final ForgingRecipe recipe; + private final List inputs; + private final List outputs; + private final List outputFailure; + private final List blueprintStacks; + + public ForgingEmiRecipe(RecipeHolder holder) { + this.id = holder.id(); + this.recipe = holder.value(); + + // Convert ingredients to EMI format + this.inputs = recipe.getIngredients().stream() + .map(EmiIngredient::of) + .toList(); + + this.outputs = List.of(EmiStack.of(recipe.getResultItem(null))); + ItemStack failureStack = recipe.getFailedResultItem(null).copy(); + failureStack.set(ModComponents.FAILED_RESULT, true); + this.outputFailure = List.of(EmiStack.of(failureStack)); + + // Create blueprint stacks for recipes that support blueprints + this.blueprintStacks = createBlueprintStacks(); +<<<<<<< HEAD +======= + + + // surfaces forging recipes that accept one + List inputList = new ArrayList<>(recipe.getIngredients().stream() + .map(EmiIngredient::of) + .toList()); + if (!blueprintStacks.isEmpty()) { + inputList.add(EmiIngredient.of(Ingredient.of(ModItems.BLUEPRINT.get()))); + } + this.inputs = inputList; +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) + } + + /** + * Create blueprint ItemStacks for this recipe's valid blueprint types. + */ + private List createBlueprintStacks() { + Set types = recipe.getBlueprintTypes(); + if (types.isEmpty()) { + return List.of(); + } + + List stacks = new ArrayList<>(); + for (String type : types) { + ItemStack stack = new ItemStack(ModItems.BLUEPRINT.get()); + // Use BlueprintData with builder pattern + BlueprintData data = BlueprintData.createDefault() + .withToolType(type); + stack.set(ModComponents.BLUEPRINT_DATA, data); + stack.set(ModComponents.BLUEPRINT_REQUIRED, recipe.requiresBlueprint()); + stacks.add(EmiStack.of(stack)); + } + return stacks; + } + + + @Override + public EmiRecipeCategory getCategory() { + return OvergearedEmiPlugin.FORGING_CATEGORY; + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public List getInputs() { + return inputs; + } + + @Override + public List getOutputs() { + return outputs; + } + + @Override + public int getDisplayWidth() { + return DISPLAY_WIDTH; + } + + @Override + public int getDisplayHeight() { + return DISPLAY_HEIGHT; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + // Blueprint slot on the left + int blueprintX = X_OFFSET; + int blueprintY = 24; + if (!blueprintStacks.isEmpty()) { + // Show blueprint variants cycling through + widgets.addSlot(EmiIngredient.of(blueprintStacks), blueprintX, blueprintY); + } else { + widgets.addSlot(EmiStack.EMPTY, blueprintX, blueprintY); + } + + // 3x3 crafting grid + int gridStartX = X_OFFSET + 24; + int gridStartY = 6; + int slotSize = 18; + + int recipeWidth = recipe.width; + int recipeHeight = recipe.height; + + NonNullList forgingIngredients = + recipe.getForgingIngredients(); + + // Create all 9 slots of the 3x3 grid + for (int row = 0; row < 3; row++) { + for (int col = 0; col < 3; col++) { + int x = gridStartX + col * slotSize; + int y = gridStartY + row * slotSize; + + int recipeIndex = row * recipeWidth + col; + + if (col < recipeWidth && row < recipeHeight && recipeIndex < forgingIngredients.size()) { + + ForgingRecipe.ForgingIngredient forgingIngredient = + forgingIngredients.get(recipeIndex); + + Ingredient ingredient = forgingIngredient.ingredient(); + + EmiIngredient emiIngredient; + + if (forgingIngredient.requiresHeated() && !containsHeatedTaggedItem(ingredient)) { + List stacks = Arrays.stream(ingredient.getItems()) + .map(stack -> { + ItemStack copy = stack.copy(); + copy.set(ModComponents.HEATED_COMPONENT, true); + return EmiStack.of(copy); + }) + .toList(); + + emiIngredient = EmiIngredient.of(stacks); + } else { + emiIngredient = EmiIngredient.of(ingredient); + } + + widgets.addSlot(emiIngredient, x, y); + } else { + widgets.addSlot(EmiStack.EMPTY, x, y); + } + } + } + + + // Arrow texture + widgets.addTexture(EmiTexture.EMPTY_ARROW, X_OFFSET + 82, 24); + + // Output slot + int outputX = X_OFFSET + 110; + int outputY = 20; + if (outputFailure.getFirst().isEmpty()) + widgets.addSlot(outputs.getFirst(), outputX, outputY).large(true).recipeContext(this); + else { + widgets.addSlot(outputs.getFirst(), outputX, outputY + 4 - 9).large(false).recipeContext(this); + widgets.addSlot(outputFailure.getFirst(), outputX, outputY + 4 + 9).large(false).recipeContext(this); + } + // Draw "Hits: X" text (top right, above arrow) + String hitsText = Component.translatable("tooltip.overgeared.recipe.hits", recipe.getRemainingHits()).getString(); + widgets.addText(Component.literal(hitsText), X_OFFSET + 82, 6, 0xFF808080, false); + + // Draw "Tier: X" text (bottom, below grid) + String tierRaw = recipe.getAnvilTier(); + AnvilTier tierEnum = AnvilTier.fromDisplayName(tierRaw); + Component tierText = Component.translatable("tooltip.overgeared.recipe.tier") + .append(Component.literal(" ")) + .append(Component.translatable(tierEnum.getLang())); + widgets.addText(tierText, X_OFFSET + 82, 54, 0xFF808080, false); + } + + private static boolean containsHeatedTaggedItem(Ingredient ingredient) { + for (ItemStack stack : ingredient.getItems()) { + if (stack.is(ModTags.Items.HEATED_METALS)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java b/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java index 28acbae0..236512ef 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/OvergearedEmiPlugin.java @@ -1,331 +1,331 @@ -package net.stirdrem.overgeared.compat.emi; - -import dev.emi.emi.api.EmiEntrypoint; -import dev.emi.emi.api.EmiPlugin; -import dev.emi.emi.api.EmiRegistry; - -import dev.emi.emi.api.recipe.EmiRecipeCategory; -import dev.emi.emi.api.render.EmiTexture; - -import dev.emi.emi.api.stack.EmiIngredient; -import dev.emi.emi.api.stack.EmiStack; - -import net.minecraft.network.chat.Component; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -<<<<<<< HEAD -======= -import net.minecraft.world.item.alchemy.Potion; ->>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) -import net.minecraft.world.item.crafting.RecipeHolder; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.material.Fluids; -import net.neoforged.neoforge.common.Tags; - -import net.stirdrem.overgeared.BlueprintQuality; -import net.stirdrem.overgeared.OvergearedMod; -import net.stirdrem.overgeared.block.ModBlocks; -import net.stirdrem.overgeared.config.ServerConfig; -import net.stirdrem.overgeared.item.ModItems; -import net.stirdrem.overgeared.recipe.*; -import net.stirdrem.overgeared.util.ModTags; - -import java.util.*; - -/** - * EMI integration for displaying Forging recipes. - * This class is only loaded when EMI is present (handled by @EmiEntrypoint). - */ -@EmiEntrypoint -public class OvergearedEmiPlugin implements EmiPlugin { - - public static final EmiStack WORKSTATION = EmiStack.of(ModBlocks.SMITHING_ANVIL.get()); - - public static final EmiRecipeCategory FORGING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("forging"), - WORKSTATION, - new EmiTexture(OvergearedMod.loc("textures/gui/smithing_anvil_jei.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.smithing_anvil"); - } - }; - - public static final EmiStack KNAPPING_WORKSTATION = EmiStack.of(ModItems.ROCK.get()); - public static final EmiRecipeCategory KNAPPING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("rock_knapping"), - KNAPPING_WORKSTATION, - new EmiTexture(OvergearedMod.loc("textures/gui/rock_knapping_gui.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.rock_knapping"); - } - }; - - public static final EmiStack ALLOY_WORKSTATION = EmiStack.of(ModBlocks.ALLOY_FURNACE.get()); - public static final EmiRecipeCategory ALLOY_SMELTING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("alloy_smelting"), - ALLOY_WORKSTATION, - new EmiTexture(OvergearedMod.loc("textures/gui/brick_alloy_furnace.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.jei.category.alloy_smelting"); - } - }; - - public static final EmiStack NETHER_ALLOY_WORKSTATION = EmiStack.of(ModBlocks.NETHER_ALLOY_FURNACE.get()); - public static final EmiRecipeCategory NETHER_ALLOY_SMELTING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("nether_alloy_smelting"), - NETHER_ALLOY_WORKSTATION, - new EmiTexture(OvergearedMod.loc("textures/gui/nether_alloy_furnace.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.jei.category.nether_alloy_smelting"); - } - }; - - public static final EmiStack FLETCHING_WORKSTATION = EmiStack.of(net.minecraft.world.level.block.Blocks.FLETCHING_TABLE); - public static final EmiRecipeCategory FLETCHING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("fletching"), - FLETCHING_WORKSTATION, - new EmiTexture(OvergearedMod.loc("textures/gui/fletching_table.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.jei.category.fletching"); - } - }; - - public static final EmiIngredient COOLING_WORKSTATION = EmiIngredient.of(List.of( - EmiStack.of(Fluids.WATER), - EmiStack.of(Blocks.WATER_CAULDRON) - )); - public static final EmiRecipeCategory COOLING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("cooling"), - EmiStack.of(Fluids.WATER), - new EmiTexture(OvergearedMod.loc("textures/gui/cooling.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.jei.category.cooling"); - } - }; - - public static final EmiStack GRINDING_WORKSTATION = EmiStack.of(Blocks.GRINDSTONE); - public static final EmiRecipeCategory GRINDING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("grinding"), - GRINDING_WORKSTATION, - new EmiTexture(OvergearedMod.loc("textures/gui/grinding.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.jei.category.grinding"); - } - }; - - public static final EmiStack CASTING_WORKSTATION = EmiStack.of(ModBlocks.CASTING_FURNACE.get()); - public static final EmiRecipeCategory CASTING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("casting"), - CASTING_WORKSTATION, - new EmiTexture(OvergearedMod.loc("textures/gui/casting_smelter.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("gui.overgeared.jei.category.casting"); - } - }; - public static final EmiStack FLINT = EmiStack.of(ModItems.ROCK); - public static final EmiRecipeCategory ROCK_GETTING_CATEGORY = new EmiRecipeCategory( - OvergearedMod.loc("flint_knapping"), - FLINT, - new EmiTexture(OvergearedMod.loc("textures/gui/flint.png"), 0, 0, 16, 16) - ) { - @Override - public Component getName() { - return Component.translatable("jei.overgeared.category.flint_knapping"); - } - }; - - // Priority for sorting recipes by category - private static final Map CATEGORY_PRIORITY = Map.of( - "tool_head", 0, - "tools", 1, - "armor", 2, - "plate", 3, - "misc", 4 - ); - - @Override - public void register(EmiRegistry registry) { - OvergearedMod.LOGGER.info("Registering EMI plugin for Overgeared recipes."); - - // Register the forging category - registry.addCategory(FORGING_CATEGORY); - - // Register all smithing anvil blocks as workstations (ordered by tier: Stone -> Iron -> A -> B) - registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.STONE_SMITHING_ANVIL.get())); - registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.SMITHING_ANVIL.get())); - registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.TIER_A_SMITHING_ANVIL.get())); - registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.TIER_B_SMITHING_ANVIL.get())); - - // Register Knapping - registry.addCategory(KNAPPING_CATEGORY); - //registry.addWorkstation(KNAPPING_CATEGORY, KNAPPING_WORKSTATION); - - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.KNAPPING.get())) { - registry.addRecipe(new KnappingEmiRecipe(holder)); - } - - // Register Alloy Smelting - registry.addCategory(ALLOY_SMELTING_CATEGORY); - registry.addWorkstation(ALLOY_SMELTING_CATEGORY, ALLOY_WORKSTATION); - - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.ALLOY_SMELTING.get())) { - registry.addRecipe(new AlloySmeltingEmiRecipe(holder)); - } - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.SHAPED_ALLOY_SMELTING.get())) { - registry.addRecipe(new ShapedAlloySmeltingEmiRecipe(holder)); - } - - // Register Nether Alloy Smelting - registry.addCategory(NETHER_ALLOY_SMELTING_CATEGORY); - registry.addWorkstation(NETHER_ALLOY_SMELTING_CATEGORY, NETHER_ALLOY_WORKSTATION); - - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.NETHER_ALLOY_SMELTING.get())) { - registry.addRecipe(new NetherAlloySmeltingEmiRecipe(holder)); - } - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.SHAPED_NETHER_ALLOY_SMELTING.get())) { - registry.addRecipe(new ShapedNetherAlloySmeltingEmiRecipe(holder)); - } - - // Register Fletching - registry.addCategory(FLETCHING_CATEGORY); - registry.addWorkstation(FLETCHING_CATEGORY, FLETCHING_WORKSTATION); - - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.FLETCHING.get())) { - registry.addRecipe(new FletchingEmiRecipe(holder)); - } - -<<<<<<< HEAD -======= - // Register per-potion tipped/lingering entries for each arrow type. - // Vanilla arrow: arrow → tipped_arrow / lingering_arrow (always shown). - // Upgrade arrows (iron/steel/diamond): only when UPGRADE_ARROW_POTION_TOGGLE is enabled. - List arrowItems = new ArrayList<>(); - arrowItems.add(Items.ARROW); // vanilla always included - if (ServerConfig.UPGRADE_ARROW_POTION_TOGGLE.get()) { - arrowItems.add(ModItems.IRON_UPGRADE_ARROW.get()); - arrowItems.add(ModItems.STEEL_UPGRADE_ARROW.get()); - arrowItems.add(ModItems.DIAMOND_UPGRADE_ARROW.get()); - } - for (Item arrowItem : arrowItems) { - for (Holder potionHolder : BuiltInRegistries.POTION.holders().toList()) { - if (potionHolder.value().getEffects().isEmpty()) continue; - ResourceLocation potionKey = BuiltInRegistries.POTION.getKey(potionHolder.value()); - if (potionKey == null) continue; - registry.addRecipe(new PotionFletchingEmiRecipe( - arrowItem, potionHolder, potionKey, PotionFletchingEmiRecipe.Variant.TIPPED)); - registry.addRecipe(new PotionFletchingEmiRecipe( - arrowItem, potionHolder, potionKey, PotionFletchingEmiRecipe.Variant.LINGERING)); - } - } - - // Register Blueprint Cloning — one entry per quality tier (crafting table) - for (BlueprintQuality quality : new BlueprintQuality[]{ - BlueprintQuality.POOR, BlueprintQuality.WELL, BlueprintQuality.EXPERT, - BlueprintQuality.PERFECT, BlueprintQuality.MASTER}) { - registry.addRecipe(new BlueprintCloningEmiRecipe(quality)); - } - - // Drafting Table explanation - registry.addCategory(DRAFTING_TABLE_CATEGORY); - registry.addWorkstation(DRAFTING_TABLE_CATEGORY, DRAFTING_TABLE_WORKSTATION); - registry.addRecipe(new DraftingTableEmiRecipe()); - ->>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) - registry.addCategory(COOLING_CATEGORY); - registry.addWorkstation(COOLING_CATEGORY, COOLING_WORKSTATION); - - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.COOLING_RECIPE.get())) { - registry.addRecipe(new CoolingEmiRecipe(holder)); - } - - registry.addCategory(GRINDING_CATEGORY); - registry.addWorkstation(GRINDING_CATEGORY, GRINDING_WORKSTATION); - - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.GRINDING_RECIPE.get())) { - registry.addRecipe(new GrindingEmiRecipe(holder)); - } - - // Register Casting - registry.addCategory(CASTING_CATEGORY); - registry.addWorkstation(CASTING_CATEGORY, CASTING_WORKSTATION); - - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.CASTING.get())) { - registry.addRecipe(new CastingEmiRecipe(holder)); - } - - if (ServerConfig.ENABLE_DRAGON_BREATH_RECIPE.get()) - registry.addRecipe(new DragonBreathEmiRecipe()); - - registry.addCategory(KNAPPING_CATEGORY); - registry.addWorkstation(KNAPPING_CATEGORY, FLINT); - if (ServerConfig.GET_ROCK_USING_FLINT.get()) - registry.addRecipe(new FlintKnappingEmiRecipe()); - - // Register Clay + Nether Tool Cast recipes (one of each per tool type) - for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.ITEM_TO_TOOLTYPE.get())) { - ItemToToolTypeRecipe recipe = holder.value(); - registry.addRecipe(new ToolCastEmiRecipe(recipe.toolType(), recipe.input(), false)); - registry.addRecipe(new ToolCastEmiRecipe(recipe.toolType(), recipe.input(), true)); - } - - // Collect and sort all forging recipes - List> allRecipes = new ArrayList<>( - registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.FORGING.get()) - ); - - // Sort recipes by category priority, then alphabetically by output name - allRecipes.sort((a, b) -> { - String catA = categorizeRecipe(a.value()); - String catB = categorizeRecipe(b.value()); - - int priorityA = CATEGORY_PRIORITY.getOrDefault(catA, 999); - int priorityB = CATEGORY_PRIORITY.getOrDefault(catB, 999); - - if (priorityA != priorityB) { - return Integer.compare(priorityA, priorityB); - } - - // Fallback: alphabetical by display name - return a.value().getResultItem(null).getDisplayName().getString() - .compareToIgnoreCase(b.value().getResultItem(null).getDisplayName().getString()); - }); - - // Add sorted recipes - for (RecipeHolder holder : allRecipes) { - registry.addRecipe(new ForgingEmiRecipe(holder)); - } - - OvergearedMod.LOGGER.info("EMI plugin registered successfully."); - } - - /** - * Categorize a recipe for sorting purposes. - */ - private static String categorizeRecipe(ForgingRecipe recipe) { - ItemStack output = recipe.getResultItem(null); - if (output.is(Tags.Items.ARMORS)) return "armor"; - if (output.is(ModTags.Items.TOOL_PARTS)) return "tool_head"; - if (output.is(Tags.Items.TOOLS)) return "tools"; - if (output.is(ModItems.IRON_PLATE.get()) || output.is(ModItems.STEEL_PLATE.get()) || output.is(ModItems.COPPER_PLATE.get())) { - return "plate"; - } - return "misc"; - } - -} +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.EmiEntrypoint; +import dev.emi.emi.api.EmiPlugin; +import dev.emi.emi.api.EmiRegistry; + +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.render.EmiTexture; + +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +<<<<<<< HEAD +======= +import net.minecraft.world.item.alchemy.Potion; +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.material.Fluids; +import net.neoforged.neoforge.common.Tags; + +import net.stirdrem.overgeared.BlueprintQuality; +import net.stirdrem.overgeared.OvergearedMod; +import net.stirdrem.overgeared.block.ModBlocks; +import net.stirdrem.overgeared.config.ServerConfig; +import net.stirdrem.overgeared.item.ModItems; +import net.stirdrem.overgeared.recipe.*; +import net.stirdrem.overgeared.util.ModTags; + +import java.util.*; + +/** + * EMI integration for displaying Forging recipes. + * This class is only loaded when EMI is present (handled by @EmiEntrypoint). + */ +@EmiEntrypoint +public class OvergearedEmiPlugin implements EmiPlugin { + + public static final EmiStack WORKSTATION = EmiStack.of(ModBlocks.SMITHING_ANVIL.get()); + + public static final EmiRecipeCategory FORGING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("forging"), + WORKSTATION, + new EmiTexture(OvergearedMod.loc("textures/gui/smithing_anvil_jei.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.smithing_anvil"); + } + }; + + public static final EmiStack KNAPPING_WORKSTATION = EmiStack.of(ModItems.ROCK.get()); + public static final EmiRecipeCategory KNAPPING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("rock_knapping"), + KNAPPING_WORKSTATION, + new EmiTexture(OvergearedMod.loc("textures/gui/rock_knapping_gui.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.rock_knapping"); + } + }; + + public static final EmiStack ALLOY_WORKSTATION = EmiStack.of(ModBlocks.ALLOY_FURNACE.get()); + public static final EmiRecipeCategory ALLOY_SMELTING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("alloy_smelting"), + ALLOY_WORKSTATION, + new EmiTexture(OvergearedMod.loc("textures/gui/brick_alloy_furnace.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.jei.category.alloy_smelting"); + } + }; + + public static final EmiStack NETHER_ALLOY_WORKSTATION = EmiStack.of(ModBlocks.NETHER_ALLOY_FURNACE.get()); + public static final EmiRecipeCategory NETHER_ALLOY_SMELTING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("nether_alloy_smelting"), + NETHER_ALLOY_WORKSTATION, + new EmiTexture(OvergearedMod.loc("textures/gui/nether_alloy_furnace.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.jei.category.nether_alloy_smelting"); + } + }; + + public static final EmiStack FLETCHING_WORKSTATION = EmiStack.of(net.minecraft.world.level.block.Blocks.FLETCHING_TABLE); + public static final EmiRecipeCategory FLETCHING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("fletching"), + FLETCHING_WORKSTATION, + new EmiTexture(OvergearedMod.loc("textures/gui/fletching_table.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.jei.category.fletching"); + } + }; + + public static final EmiIngredient COOLING_WORKSTATION = EmiIngredient.of(List.of( + EmiStack.of(Fluids.WATER), + EmiStack.of(Blocks.WATER_CAULDRON) + )); + public static final EmiRecipeCategory COOLING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("cooling"), + EmiStack.of(Fluids.WATER), + new EmiTexture(OvergearedMod.loc("textures/gui/cooling.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.jei.category.cooling"); + } + }; + + public static final EmiStack GRINDING_WORKSTATION = EmiStack.of(Blocks.GRINDSTONE); + public static final EmiRecipeCategory GRINDING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("grinding"), + GRINDING_WORKSTATION, + new EmiTexture(OvergearedMod.loc("textures/gui/grinding.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.jei.category.grinding"); + } + }; + + public static final EmiStack CASTING_WORKSTATION = EmiStack.of(ModBlocks.CASTING_FURNACE.get()); + public static final EmiRecipeCategory CASTING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("casting"), + CASTING_WORKSTATION, + new EmiTexture(OvergearedMod.loc("textures/gui/casting_smelter.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("gui.overgeared.jei.category.casting"); + } + }; + public static final EmiStack FLINT = EmiStack.of(ModItems.ROCK); + public static final EmiRecipeCategory ROCK_GETTING_CATEGORY = new EmiRecipeCategory( + OvergearedMod.loc("flint_knapping"), + FLINT, + new EmiTexture(OvergearedMod.loc("textures/gui/flint.png"), 0, 0, 16, 16) + ) { + @Override + public Component getName() { + return Component.translatable("jei.overgeared.category.flint_knapping"); + } + }; + + // Priority for sorting recipes by category + private static final Map CATEGORY_PRIORITY = Map.of( + "tool_head", 0, + "tools", 1, + "armor", 2, + "plate", 3, + "misc", 4 + ); + + @Override + public void register(EmiRegistry registry) { + OvergearedMod.LOGGER.info("Registering EMI plugin for Overgeared recipes."); + + // Register the forging category + registry.addCategory(FORGING_CATEGORY); + + // Register all smithing anvil blocks as workstations (ordered by tier: Stone -> Iron -> A -> B) + registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.STONE_SMITHING_ANVIL.get())); + registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.SMITHING_ANVIL.get())); + registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.TIER_A_SMITHING_ANVIL.get())); + registry.addWorkstation(FORGING_CATEGORY, EmiStack.of(ModBlocks.TIER_B_SMITHING_ANVIL.get())); + + // Register Knapping + registry.addCategory(KNAPPING_CATEGORY); + //registry.addWorkstation(KNAPPING_CATEGORY, KNAPPING_WORKSTATION); + + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.KNAPPING.get())) { + registry.addRecipe(new KnappingEmiRecipe(holder)); + } + + // Register Alloy Smelting + registry.addCategory(ALLOY_SMELTING_CATEGORY); + registry.addWorkstation(ALLOY_SMELTING_CATEGORY, ALLOY_WORKSTATION); + + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.ALLOY_SMELTING.get())) { + registry.addRecipe(new AlloySmeltingEmiRecipe(holder)); + } + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.SHAPED_ALLOY_SMELTING.get())) { + registry.addRecipe(new ShapedAlloySmeltingEmiRecipe(holder)); + } + + // Register Nether Alloy Smelting + registry.addCategory(NETHER_ALLOY_SMELTING_CATEGORY); + registry.addWorkstation(NETHER_ALLOY_SMELTING_CATEGORY, NETHER_ALLOY_WORKSTATION); + + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.NETHER_ALLOY_SMELTING.get())) { + registry.addRecipe(new NetherAlloySmeltingEmiRecipe(holder)); + } + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.SHAPED_NETHER_ALLOY_SMELTING.get())) { + registry.addRecipe(new ShapedNetherAlloySmeltingEmiRecipe(holder)); + } + + // Register Fletching + registry.addCategory(FLETCHING_CATEGORY); + registry.addWorkstation(FLETCHING_CATEGORY, FLETCHING_WORKSTATION); + + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.FLETCHING.get())) { + registry.addRecipe(new FletchingEmiRecipe(holder)); + } + +<<<<<<< HEAD +======= + // Register per-potion tipped/lingering entries for each arrow type. + // Vanilla arrow: arrow → tipped_arrow / lingering_arrow (always shown). + // Upgrade arrows (iron/steel/diamond): only when UPGRADE_ARROW_POTION_TOGGLE is enabled. + List arrowItems = new ArrayList<>(); + arrowItems.add(Items.ARROW); // vanilla always included + if (ServerConfig.UPGRADE_ARROW_POTION_TOGGLE.get()) { + arrowItems.add(ModItems.IRON_UPGRADE_ARROW.get()); + arrowItems.add(ModItems.STEEL_UPGRADE_ARROW.get()); + arrowItems.add(ModItems.DIAMOND_UPGRADE_ARROW.get()); + } + for (Item arrowItem : arrowItems) { + for (Holder potionHolder : BuiltInRegistries.POTION.holders().toList()) { + if (potionHolder.value().getEffects().isEmpty()) continue; + ResourceLocation potionKey = BuiltInRegistries.POTION.getKey(potionHolder.value()); + if (potionKey == null) continue; + registry.addRecipe(new PotionFletchingEmiRecipe( + arrowItem, potionHolder, potionKey, PotionFletchingEmiRecipe.Variant.TIPPED)); + registry.addRecipe(new PotionFletchingEmiRecipe( + arrowItem, potionHolder, potionKey, PotionFletchingEmiRecipe.Variant.LINGERING)); + } + } + + // Register Blueprint Cloning — one entry per quality tier (crafting table) + for (BlueprintQuality quality : new BlueprintQuality[]{ + BlueprintQuality.POOR, BlueprintQuality.WELL, BlueprintQuality.EXPERT, + BlueprintQuality.PERFECT, BlueprintQuality.MASTER}) { + registry.addRecipe(new BlueprintCloningEmiRecipe(quality)); + } + + // Drafting Table explanation + registry.addCategory(DRAFTING_TABLE_CATEGORY); + registry.addWorkstation(DRAFTING_TABLE_CATEGORY, DRAFTING_TABLE_WORKSTATION); + registry.addRecipe(new DraftingTableEmiRecipe()); + +>>>>>>> f185c2b (fix: add missing EMI entries for blueprint cloning, tipped/lingering arrows and forging blueprint usage) + registry.addCategory(COOLING_CATEGORY); + registry.addWorkstation(COOLING_CATEGORY, COOLING_WORKSTATION); + + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.COOLING_RECIPE.get())) { + registry.addRecipe(new CoolingEmiRecipe(holder)); + } + + registry.addCategory(GRINDING_CATEGORY); + registry.addWorkstation(GRINDING_CATEGORY, GRINDING_WORKSTATION); + + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.GRINDING_RECIPE.get())) { + registry.addRecipe(new GrindingEmiRecipe(holder)); + } + + // Register Casting + registry.addCategory(CASTING_CATEGORY); + registry.addWorkstation(CASTING_CATEGORY, CASTING_WORKSTATION); + + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.CASTING.get())) { + registry.addRecipe(new CastingEmiRecipe(holder)); + } + + if (ServerConfig.ENABLE_DRAGON_BREATH_RECIPE.get()) + registry.addRecipe(new DragonBreathEmiRecipe()); + + registry.addCategory(KNAPPING_CATEGORY); + registry.addWorkstation(KNAPPING_CATEGORY, FLINT); + if (ServerConfig.GET_ROCK_USING_FLINT.get()) + registry.addRecipe(new FlintKnappingEmiRecipe()); + + // Register Clay + Nether Tool Cast recipes (one of each per tool type) + for (RecipeHolder holder : registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.ITEM_TO_TOOLTYPE.get())) { + ItemToToolTypeRecipe recipe = holder.value(); + registry.addRecipe(new ToolCastEmiRecipe(recipe.toolType(), recipe.input(), false)); + registry.addRecipe(new ToolCastEmiRecipe(recipe.toolType(), recipe.input(), true)); + } + + // Collect and sort all forging recipes + List> allRecipes = new ArrayList<>( + registry.getRecipeManager().getAllRecipesFor(ModRecipeTypes.FORGING.get()) + ); + + // Sort recipes by category priority, then alphabetically by output name + allRecipes.sort((a, b) -> { + String catA = categorizeRecipe(a.value()); + String catB = categorizeRecipe(b.value()); + + int priorityA = CATEGORY_PRIORITY.getOrDefault(catA, 999); + int priorityB = CATEGORY_PRIORITY.getOrDefault(catB, 999); + + if (priorityA != priorityB) { + return Integer.compare(priorityA, priorityB); + } + + // Fallback: alphabetical by display name + return a.value().getResultItem(null).getDisplayName().getString() + .compareToIgnoreCase(b.value().getResultItem(null).getDisplayName().getString()); + }); + + // Add sorted recipes + for (RecipeHolder holder : allRecipes) { + registry.addRecipe(new ForgingEmiRecipe(holder)); + } + + OvergearedMod.LOGGER.info("EMI plugin registered successfully."); + } + + /** + * Categorize a recipe for sorting purposes. + */ + private static String categorizeRecipe(ForgingRecipe recipe) { + ItemStack output = recipe.getResultItem(null); + if (output.is(Tags.Items.ARMORS)) return "armor"; + if (output.is(ModTags.Items.TOOL_PARTS)) return "tool_head"; + if (output.is(Tags.Items.TOOLS)) return "tools"; + if (output.is(ModItems.IRON_PLATE.get()) || output.is(ModItems.STEEL_PLATE.get()) || output.is(ModItems.COPPER_PLATE.get())) { + return "plate"; + } + return "misc"; + } + +} diff --git a/src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java b/src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java index 91892184..41799a7c 100644 --- a/src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java +++ b/src/main/java/net/stirdrem/overgeared/compat/emi/PotionFletchingEmiRecipe.java @@ -1,133 +1,133 @@ -package net.stirdrem.overgeared.compat.emi; - -import dev.emi.emi.api.recipe.EmiRecipe; -import dev.emi.emi.api.recipe.EmiRecipeCategory; -import dev.emi.emi.api.render.EmiTexture; -import dev.emi.emi.api.stack.Comparison; -import dev.emi.emi.api.stack.EmiIngredient; -import dev.emi.emi.api.stack.EmiStack; -import dev.emi.emi.api.widget.WidgetHolder; -import net.minecraft.core.Holder; -import net.minecraft.core.component.DataComponents; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.alchemy.Potion; -import net.minecraft.world.item.alchemy.PotionContents; -import net.stirdrem.overgeared.OvergearedMod; -import net.stirdrem.overgeared.components.ModComponents; -import net.stirdrem.overgeared.item.ModItems; - -import java.util.List; - -/** - * EMI recipe entry for arrow and potion conversion in the fletching table (Path 1). - * - Arrow in the TIP slot, shaft and feather empty, potion in potion slot - * - One entry per: arrow type × potion × variant (TIPPED / LINGERING) - * - Includes vanilla arrow (→ tipped_arrow / lingering_arrow) - * - Includes upgrade arrows (iron/steel/diamond → same item + POTION_CONTENTS) - */ -public class PotionFletchingEmiRecipe implements EmiRecipe { - - public enum Variant { TIPPED, LINGERING } - - private static final int SLOT_SIZE = 18; - - private final ResourceLocation id; - private final Variant variant; - private final List inputs; - private final List outputs; - - public PotionFletchingEmiRecipe(Item arrowItem, Holder potion, - ResourceLocation potionKey, Variant variant) { - String arrowPath = arrowItem.builtInRegistryHolder().key().location().getPath(); - this.id = OvergearedMod.loc("fletching/" + variant.name().toLowerCase() - + "_conv/" + arrowPath + "/" + potionKey.getPath()); - this.variant = variant; - - // Input: 1x base arrow (goes in tip slot) - ItemStack arrowInput = new ItemStack(arrowItem, 1); - - // Input: specific potion - Item potionItem = variant == Variant.TIPPED ? Items.POTION : Items.LINGERING_POTION; - ItemStack potionStack = PotionContents.createItemStack(potionItem, potion); - - this.inputs = List.of(EmiStack.of(arrowInput), EmiStack.of(potionStack)); - - // Output depends on arrow type and variant - PotionContents contents = potionStack.get(DataComponents.POTION_CONTENTS); - ItemStack output; - - if (arrowItem == Items.ARROW) { - // Vanilla arrow → tipped_arrow or lingering_arrow (different items) - if (variant == Variant.TIPPED) { - output = new ItemStack(Items.TIPPED_ARROW, 1); - } else { - output = new ItemStack(ModItems.LINGERING_ARROW.get(), 1); - } - } else { - // Upgrade arrow → same item with potion contents - output = new ItemStack(arrowItem, 1); - if (variant == Variant.LINGERING) { - output.set(ModComponents.LINGERING_STATUS, true); - } - } - if (contents != null) output.set(DataComponents.POTION_CONTENTS, contents); - - // only shows THIS recipe, not all tipped/lingering recipes for this arrow. - EmiStack outputStack = EmiStack.of(output).comparison(Comparison.compareComponents()); - this.outputs = List.of(outputStack); - } - - @Override - public EmiRecipeCategory getCategory() { - return OvergearedEmiPlugin.FLETCHING_CATEGORY; - } - - @Override - public ResourceLocation getId() { - return id; - } - - @Override - public List getInputs() { - return inputs; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public int getDisplayWidth() { - return 120; - } - - @Override - public int getDisplayHeight() { - return 60; - } - - @Override - public void addWidgets(WidgetHolder widgets) { - int offsetX = 4; - int offsetY = 4; - - // Arrow in shaft slot (middle) for aesthetics, tip and feather empty - widgets.addSlot(EmiStack.EMPTY, offsetX + 36, offsetY); - widgets.addSlot(inputs.get(0), offsetX + 18, offsetY + SLOT_SIZE); - widgets.addSlot(EmiStack.EMPTY, offsetX, offsetY + SLOT_SIZE * 2); - - // Potion in potion slot (bottom-right) - widgets.addSlot(inputs.get(1), offsetX + 36, offsetY + SLOT_SIZE * 2); - - // Arrow - widgets.addTexture(EmiTexture.EMPTY_ARROW, offsetX + 54, offsetY + SLOT_SIZE); - - // Output - widgets.addSlot(outputs.getFirst(), offsetX + 82, offsetY + SLOT_SIZE - 4) - .large(true).recipeContext(this); - } -} +package net.stirdrem.overgeared.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.Comparison; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.WidgetHolder; +import net.minecraft.core.Holder; +import net.minecraft.core.component.DataComponents; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.PotionContents; +import net.stirdrem.overgeared.OvergearedMod; +import net.stirdrem.overgeared.components.ModComponents; +import net.stirdrem.overgeared.item.ModItems; + +import java.util.List; + +/** + * EMI recipe entry for arrow and potion conversion in the fletching table (Path 1). + * - Arrow in the TIP slot, shaft and feather empty, potion in potion slot + * - One entry per: arrow type × potion × variant (TIPPED / LINGERING) + * - Includes vanilla arrow (→ tipped_arrow / lingering_arrow) + * - Includes upgrade arrows (iron/steel/diamond → same item + POTION_CONTENTS) + */ +public class PotionFletchingEmiRecipe implements EmiRecipe { + + public enum Variant { TIPPED, LINGERING } + + private static final int SLOT_SIZE = 18; + + private final ResourceLocation id; + private final Variant variant; + private final List inputs; + private final List outputs; + + public PotionFletchingEmiRecipe(Item arrowItem, Holder potion, + ResourceLocation potionKey, Variant variant) { + String arrowPath = arrowItem.builtInRegistryHolder().key().location().getPath(); + this.id = OvergearedMod.loc("fletching/" + variant.name().toLowerCase() + + "_conv/" + arrowPath + "/" + potionKey.getPath()); + this.variant = variant; + + // Input: 1x base arrow (goes in tip slot) + ItemStack arrowInput = new ItemStack(arrowItem, 1); + + // Input: specific potion + Item potionItem = variant == Variant.TIPPED ? Items.POTION : Items.LINGERING_POTION; + ItemStack potionStack = PotionContents.createItemStack(potionItem, potion); + + this.inputs = List.of(EmiStack.of(arrowInput), EmiStack.of(potionStack)); + + // Output depends on arrow type and variant + PotionContents contents = potionStack.get(DataComponents.POTION_CONTENTS); + ItemStack output; + + if (arrowItem == Items.ARROW) { + // Vanilla arrow → tipped_arrow or lingering_arrow (different items) + if (variant == Variant.TIPPED) { + output = new ItemStack(Items.TIPPED_ARROW, 1); + } else { + output = new ItemStack(ModItems.LINGERING_ARROW.get(), 1); + } + } else { + // Upgrade arrow → same item with potion contents + output = new ItemStack(arrowItem, 1); + if (variant == Variant.LINGERING) { + output.set(ModComponents.LINGERING_STATUS, true); + } + } + if (contents != null) output.set(DataComponents.POTION_CONTENTS, contents); + + // only shows THIS recipe, not all tipped/lingering recipes for this arrow. + EmiStack outputStack = EmiStack.of(output).comparison(Comparison.compareComponents()); + this.outputs = List.of(outputStack); + } + + @Override + public EmiRecipeCategory getCategory() { + return OvergearedEmiPlugin.FLETCHING_CATEGORY; + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public List getInputs() { + return inputs; + } + + @Override + public List getOutputs() { + return outputs; + } + + @Override + public int getDisplayWidth() { + return 120; + } + + @Override + public int getDisplayHeight() { + return 60; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + int offsetX = 4; + int offsetY = 4; + + // Arrow in shaft slot (middle) for aesthetics, tip and feather empty + widgets.addSlot(EmiStack.EMPTY, offsetX + 36, offsetY); + widgets.addSlot(inputs.get(0), offsetX + 18, offsetY + SLOT_SIZE); + widgets.addSlot(EmiStack.EMPTY, offsetX, offsetY + SLOT_SIZE * 2); + + // Potion in potion slot (bottom-right) + widgets.addSlot(inputs.get(1), offsetX + 36, offsetY + SLOT_SIZE * 2); + + // Arrow + widgets.addTexture(EmiTexture.EMPTY_ARROW, offsetX + 54, offsetY + SLOT_SIZE); + + // Output + widgets.addSlot(outputs.getFirst(), offsetX + 82, offsetY + SLOT_SIZE - 4) + .large(true).recipeContext(this); + } +} diff --git a/src/main/resources/assets/overgeared/lang/en_us.json b/src/main/resources/assets/overgeared/lang/en_us.json index 792dceac..96105ed8 100644 --- a/src/main/resources/assets/overgeared/lang/en_us.json +++ b/src/main/resources/assets/overgeared/lang/en_us.json @@ -205,6 +205,8 @@ "tooltip.overgeared.potion_uses": "Tipping Uses Left: %s/%s", "jei.overgeared.category.steel_anvil": "How to make Smithing Anvil", "jei.overgeared.steel_anvil.description": "Crouch right click on a vanilla Anvil with a Smithing Hammer to convert it to a Smithing Anvil.", + "jei.overgeared.category.drafting_table": "Drafting Table", + "jei.overgeared.drafting_table.description": "Use the Drafting Table to turn an Empty Blueprint into a Smithing Blueprint for a chosen tool type.", "creativetab.overgeared.lingering_arrows_tab": "Fletching and Arrows", "container.overgeared.fletching_table": "Fletching", "creativetab.overgeared.blueprint_tab": "Smithing Blueprints",