From d1f42ed322bdff926eab18fb02fcd22cf8b3a6e6 Mon Sep 17 00:00:00 2001 From: Sarim Khan Date: Thu, 30 May 2024 00:30:45 +0600 Subject: [PATCH] Chipped: recipe viewer and handler integration --- build.gradle | 18 +++ gradle.properties | 4 + .../AbstractChippedIntegration.java | 32 ++++ .../extramodintegrations/ExMIPlugin.java | 1 + .../chipped/ChippedEmiRecipe.java | 35 +++++ .../chipped/ChippedIntegration.java | 137 ++++++++++++++++++ .../chipped/ChippedWorkbenchHandler.java | 67 +++++++++ 7 files changed, 294 insertions(+) create mode 100644 src/main/java/com/kneelawk/extramodintegrations/AbstractChippedIntegration.java create mode 100644 src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedEmiRecipe.java create mode 100644 src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedIntegration.java create mode 100644 src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedWorkbenchHandler.java diff --git a/build.gradle b/build.gradle index 51c67ce..6b7ae1e 100644 --- a/build.gradle +++ b/build.gradle @@ -159,6 +159,19 @@ repositories { includeGroup "me.shedaniel.cloth" } } + + maven { + // Teamresourceful, required by Chipped + name "Teamresourceful" + url "https://maven.teamresourceful.com/repository/maven-public" + content { + includeGroup "earth.terrarium.chipped" + includeGroup "com.teamresourceful.resourcefullib" + includeGroup "com.teamresourceful" + includeGroup "earth.terrarium.athena" + includeGroup "com.terraformersmc" + } + } } dependencies { @@ -258,6 +271,11 @@ dependencies { dependencies.ext.mod "com.github.Chocohead:Fabric-ASM:v2.3" } + // Chipped + if (chipped_enabled) { + dependencies.ext.mod "earth.terrarium.chipped:chipped-fabric-${minecraft_version}:${chipped_version}" + } + // // Stuff we just want to have at runtime // diff --git a/gradle.properties b/gradle.properties index e2f71c5..abd0a54 100644 --- a/gradle.properties +++ b/gradle.properties @@ -78,5 +78,9 @@ arch_version = 9.2.14 cloth_version = 11.1.118 cca_version = 5.2.2 +# Chipped +chipped_enabled = true +chipped_version = 3.0.6 + # Runtime Mod Dependencies mod_menu_version = 7.2.1 diff --git a/src/main/java/com/kneelawk/extramodintegrations/AbstractChippedIntegration.java b/src/main/java/com/kneelawk/extramodintegrations/AbstractChippedIntegration.java new file mode 100644 index 0000000..4b04bc2 --- /dev/null +++ b/src/main/java/com/kneelawk/extramodintegrations/AbstractChippedIntegration.java @@ -0,0 +1,32 @@ +package com.kneelawk.extramodintegrations; + +import com.kneelawk.extramodintegrations.util.ReflectionUtils; +import dev.emi.emi.api.EmiRegistry; +import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.Nullable; + +public abstract class AbstractChippedIntegration { + @Nullable + public static final AbstractChippedIntegration INSTANCE; + + static { + if (FabricLoader.getInstance().isModLoaded("chipped")) { + INSTANCE = + ReflectionUtils.newIntegrationInstance("com.kneelawk.extramodintegrations.chipped.ChippedIntegration", + "Chipped"); + } else { + INSTANCE = null; + } + } + + protected abstract void registerImpl(EmiRegistry registry); + + public static void register(EmiRegistry registry) { + if (INSTANCE != null) { + INSTANCE.registerImpl(registry); + } else { + ExMIMod.logSkipping("Chipped"); + } + } + +} diff --git a/src/main/java/com/kneelawk/extramodintegrations/ExMIPlugin.java b/src/main/java/com/kneelawk/extramodintegrations/ExMIPlugin.java index 5956dc5..a811c77 100644 --- a/src/main/java/com/kneelawk/extramodintegrations/ExMIPlugin.java +++ b/src/main/java/com/kneelawk/extramodintegrations/ExMIPlugin.java @@ -34,6 +34,7 @@ public void register(EmiRegistry registry) { AbstractAE2Integration.register(registry); AbstractTiCIntegration.register(registry); AbstractDimDoorsIntegration.register(registry); + AbstractChippedIntegration.register(registry); } @Override diff --git a/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedEmiRecipe.java b/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedEmiRecipe.java new file mode 100644 index 0000000..3af7e19 --- /dev/null +++ b/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedEmiRecipe.java @@ -0,0 +1,35 @@ +package com.kneelawk.extramodintegrations.chipped; + +import com.kneelawk.extramodintegrations.ExMIMod; +import dev.emi.emi.api.recipe.BasicEmiRecipe; +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.item.ItemStack; +import net.minecraft.recipe.Ingredient; +import net.minecraft.util.Identifier; + +public class ChippedEmiRecipe extends BasicEmiRecipe { + + public ChippedEmiRecipe(EmiRecipeCategory category, FlattenedRecipe recipe) { + super(category, new Identifier(ExMIMod.MOD_ID, "/chipped/" + recipe.id), 80, 18); + this.inputs.add(EmiIngredient.of(recipe.tag)); + this.outputs.add(EmiStack.of(recipe.result)); + } + + @Override + public void addWidgets(WidgetHolder widgets) { + widgets.addTexture(EmiTexture.EMPTY_ARROW, 26, 1); + widgets.addSlot(inputs.get(0), 0, 0); + widgets.addSlot(outputs.get(0), 58, 0).recipeContext(this); + } + + public record FlattenedRecipe( + String id, + Ingredient tag, + ItemStack result + ) { + } +} diff --git a/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedIntegration.java b/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedIntegration.java new file mode 100644 index 0000000..9dc0ebb --- /dev/null +++ b/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedIntegration.java @@ -0,0 +1,137 @@ +package com.kneelawk.extramodintegrations.chipped; + +import com.kneelawk.extramodintegrations.AbstractChippedIntegration; +import com.kneelawk.extramodintegrations.ExMIMod; +import dev.emi.emi.api.EmiRegistry; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.stack.EmiStack; +import earth.terrarium.chipped.common.recipes.ChippedRecipe; +import earth.terrarium.chipped.common.registry.ModBlocks; +import earth.terrarium.chipped.common.registry.ModMenuTypes; +import earth.terrarium.chipped.common.registry.ModRecipeTypes; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.Ingredient; +import net.minecraft.recipe.RecipeManager; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryEntryList; +import net.minecraft.text.Text; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class ChippedIntegration extends AbstractChippedIntegration { + + public static final EmiRecipeCategory BOTANIST_WORKBENCH_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.BOTANIST_WORKBENCH); + public static final EmiRecipeCategory GLASSBLOWER_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.GLASSBLOWER); + public static final EmiRecipeCategory CARPENTERS_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.CARPENTERS_TABLE); + public static final EmiRecipeCategory LOOM_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.LOOM_TABLE); + public static final EmiRecipeCategory MASON_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.MASON_TABLE); + public static final EmiRecipeCategory ALCHEMY_BENCH_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.ALCHEMY_BENCH); + public static final EmiRecipeCategory TINKERING_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.TINKERING_TABLE); + + private static List flatten(Collection recipes) { + List flattenedRecipes = new ArrayList<>(); + + for (ChippedRecipe recipe : recipes) { + for (RegistryEntryList tag : recipe.tags()) { + List items = tag.stream().filter(RegistryEntry::hasKeyAndValue).map(RegistryEntry::value).toList(); + Ingredient ingredient = Ingredient.ofStacks(items.stream().map(ItemStack::new)); + + for (Item item : items) { + flattenedRecipes.add(new ChippedEmiRecipe.FlattenedRecipe(item.toString(), ingredient, new ItemStack(item))); + } + } + } + return flattenedRecipes; + } + + @Override + protected void registerImpl(EmiRegistry registry) { + + ExMIMod.logLoading("Chipped"); + + // categories + registry.addCategory(BOTANIST_WORKBENCH_CATEGORY); + registry.addCategory(GLASSBLOWER_CATEGORY); + registry.addCategory(CARPENTERS_TABLE_CATEGORY); + registry.addCategory(LOOM_TABLE_CATEGORY); + registry.addCategory(MASON_TABLE_CATEGORY); + registry.addCategory(ALCHEMY_BENCH_CATEGORY); + registry.addCategory(TINKERING_TABLE_CATEGORY); + + // workstations + registry.addWorkstation(BOTANIST_WORKBENCH_CATEGORY, EmiStack.of(ModBlocks.BOTANIST_WORKBENCH.get())); + registry.addWorkstation(GLASSBLOWER_CATEGORY, EmiStack.of(ModBlocks.GLASSBLOWER.get())); + registry.addWorkstation(CARPENTERS_TABLE_CATEGORY, EmiStack.of(ModBlocks.CARPENTERS_TABLE.get())); + registry.addWorkstation(LOOM_TABLE_CATEGORY, EmiStack.of(ModBlocks.LOOM_TABLE.get())); + registry.addWorkstation(MASON_TABLE_CATEGORY, EmiStack.of(ModBlocks.MASON_TABLE.get())); + registry.addWorkstation(ALCHEMY_BENCH_CATEGORY, EmiStack.of(ModBlocks.ALCHEMY_BENCH.get())); + registry.addWorkstation(TINKERING_TABLE_CATEGORY, EmiStack.of(ModBlocks.TINKERING_TABLE.get())); + + // handler + registry.addRecipeHandler(ModMenuTypes.WORKBENCH.get(), new ChippedWorkbenchHandler()); + + // recipes + RecipeManager manager = registry.getRecipeManager(); + + // Botanist Workbench Recipes + flatten(manager.listAllOfType(ModRecipeTypes.BOTANIST_WORKBENCH.get())) + .stream() + .map(recipe -> new ChippedEmiRecipe(BOTANIST_WORKBENCH_CATEGORY, recipe)) + .forEach(registry::addRecipe); + + // Glassblower Recipes + flatten(manager.listAllOfType(ModRecipeTypes.GLASSBLOWER.get())) + .stream() + .map(recipe -> new ChippedEmiRecipe(GLASSBLOWER_CATEGORY, recipe)) + .forEach(registry::addRecipe); + + // Carpenters Table Recipes + flatten(manager.listAllOfType(ModRecipeTypes.CARPENTERS_TABLE.get())) + .stream() + .map(recipe -> new ChippedEmiRecipe(CARPENTERS_TABLE_CATEGORY, recipe)) + .forEach(registry::addRecipe); + + // Loom Table Recipes + flatten(manager.listAllOfType(ModRecipeTypes.LOOM_TABLE.get())) + .stream() + .map(recipe -> new ChippedEmiRecipe(LOOM_TABLE_CATEGORY, recipe)) + .forEach(registry::addRecipe); + + // Mason Table Recipes + flatten(manager.listAllOfType(ModRecipeTypes.MASON_TABLE.get())) + .stream() + .map(recipe -> new ChippedEmiRecipe(MASON_TABLE_CATEGORY, recipe)) + .forEach(registry::addRecipe); + + // Alchemy Bench Recipes + flatten(manager.listAllOfType(ModRecipeTypes.ALCHEMY_BENCH.get())) + .stream() + .map(recipe -> new ChippedEmiRecipe(ALCHEMY_BENCH_CATEGORY, recipe)) + .forEach(registry::addRecipe); + + // Tinkering Table Recipes + flatten(manager.listAllOfType(ModRecipeTypes.TINKERING_TABLE.get())) + .stream() + .map(recipe -> new ChippedEmiRecipe(TINKERING_TABLE_CATEGORY, recipe)) + .forEach(registry::addRecipe); + + } + + public static class ChippedEmiRecipeCategory extends EmiRecipeCategory { + private final Block block; + + public ChippedEmiRecipeCategory(com.teamresourceful.resourcefullib.common.registry.RegistryEntry block) { + super(block.getId(), EmiStack.of(block.get())); + this.block = block.get(); + } + + @Override + public Text getName() { + return block.getName(); + } + } +} diff --git a/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedWorkbenchHandler.java b/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedWorkbenchHandler.java new file mode 100644 index 0000000..18f84e6 --- /dev/null +++ b/src/main/java/com/kneelawk/extramodintegrations/chipped/ChippedWorkbenchHandler.java @@ -0,0 +1,67 @@ +package com.kneelawk.extramodintegrations.chipped; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.handler.EmiCraftContext; +import dev.emi.emi.api.recipe.handler.StandardRecipeHandler; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import earth.terrarium.chipped.common.menus.WorkbenchMenu; +import net.minecraft.client.MinecraftClient; +import net.minecraft.item.Item; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; + +import java.util.List; + +public class ChippedWorkbenchHandler implements StandardRecipeHandler { + + @Override + public List getInputSources(WorkbenchMenu handler) { + return handler.slots.subList(0, 35); + } + + @Override + public List getCraftingSlots(WorkbenchMenu handler) { + return List.of(); + } + + @Override + public boolean supportsRecipe(EmiRecipe recipe) { + return recipe.getCategory() instanceof ChippedIntegration.ChippedEmiRecipeCategory; // && correct table. + } + + @Override + public boolean canCraft(EmiRecipe recipe, EmiCraftContext context) { + return recipe.getCategory().getName().getString().equals(context.getScreen().getTitle().getString()) && context.getInventory().canCraft(recipe); + } + + @Override + public boolean craft(EmiRecipe recipe, EmiCraftContext context) { + + // context.getAmount(). Amount doesn't apply to Chipped Workbench. + MinecraftClient client = MinecraftClient.getInstance(); + + List slots = getInputSources(context.getScreenHandler()); + EmiIngredient ingredient = recipe.getInputs().get(0); + Item output = recipe.getOutputs().get(0).getItemStack().getItem(); + + for (int i = 0; i < slots.size(); i++) { + EmiStack slotStack = EmiStack.of(slots.get(i).getStack()); + if (ingredient.getEmiStacks().contains(slotStack)) { + // Technically this should work, looks ok in client side, but server refuses to actually craft. + // So used client.interactionManager to simulate real click. + // context.getScreenHandler().selectStack(i); + client.interactionManager.clickSlot(context.getScreenHandler().syncId, i, 0, SlotActionType.PICKUP, client.player); + context.getScreenHandler().results().stream() + .filter(s -> s.getItem().equals(output)) + .findFirst() + .ifPresent(itemStack -> context.getScreenHandler().setChosenStack(itemStack)); + + MinecraftClient.getInstance().setScreen(context.getScreen()); + return true; + } + } + + return false; + } +}