From 15d6b422e91197ac637b2993109710fe4bcca44e Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Tue, 30 Jul 2024 00:05:40 +0300 Subject: [PATCH] Rewrite EMI compat in Java --- .../adorn/compat/emi/AdornEmiPlugin.java | 52 +++++++++ .../adorn/compat/emi/BrewingEmiRecipe.java | 110 ++++++++++++++++++ .../java/juuxel/adorn/compat/emi/EmiUtil.java | 34 ++++++ .../emi/TradingStationDragDropHandler.java | 35 ++++++ .../juuxel/adorn/fluid/FluidIngredient.java | 2 - .../juuxel/adorn/compat/emi/AdornEmiPlugin.kt | 50 -------- .../adorn/compat/emi/BrewingEmiRecipe.kt | 90 -------------- .../juuxel/adorn/compat/emi/Extensions.kt | 25 ---- .../emi/TradingStationDragDropHandler.kt | 25 ---- 9 files changed, 231 insertions(+), 192 deletions(-) create mode 100644 common/src/main/java/juuxel/adorn/compat/emi/AdornEmiPlugin.java create mode 100644 common/src/main/java/juuxel/adorn/compat/emi/BrewingEmiRecipe.java create mode 100644 common/src/main/java/juuxel/adorn/compat/emi/EmiUtil.java create mode 100644 common/src/main/java/juuxel/adorn/compat/emi/TradingStationDragDropHandler.java delete mode 100644 common/src/main/kotlin/juuxel/adorn/compat/emi/AdornEmiPlugin.kt delete mode 100644 common/src/main/kotlin/juuxel/adorn/compat/emi/BrewingEmiRecipe.kt delete mode 100644 common/src/main/kotlin/juuxel/adorn/compat/emi/Extensions.kt delete mode 100644 common/src/main/kotlin/juuxel/adorn/compat/emi/TradingStationDragDropHandler.kt diff --git a/common/src/main/java/juuxel/adorn/compat/emi/AdornEmiPlugin.java b/common/src/main/java/juuxel/adorn/compat/emi/AdornEmiPlugin.java new file mode 100644 index 000000000..499a00e37 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/compat/emi/AdornEmiPlugin.java @@ -0,0 +1,52 @@ +package juuxel.adorn.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.EmiStack; +import juuxel.adorn.AdornCommon; +import juuxel.adorn.block.AdornBlocks; +import juuxel.adorn.client.gui.screen.TradingStationScreen; +import juuxel.adorn.recipe.AdornRecipes; +import juuxel.adorn.recipe.FluidBrewingRecipe; +import juuxel.adorn.recipe.ItemBrewingRecipe; +import juuxel.adorn.util.Logging; +import org.slf4j.Logger; + +@EmiEntrypoint +public final class AdornEmiPlugin implements EmiPlugin { + private static final Logger LOGGER = Logging.logger(); + + public static final EmiRecipeCategory BREWER_CATEGORY = new EmiRecipeCategory( + AdornCommon.id("brewer"), + EmiStack.of(AdornBlocks.INSTANCE.getBREWER()), + new EmiTexture(AdornCommon.id("textures/gui/recipe_viewer/brewer_light.png"), 240, 0, 16, 16) + ); + + @Override + public void register(EmiRegistry registry) { + registry.addCategory(BREWER_CATEGORY); + registry.addWorkstation(BREWER_CATEGORY, EmiStack.of(AdornBlocks.INSTANCE.getBREWER())); + + var recipeManager = registry.getRecipeManager(); + + for (var entry : recipeManager.listAllOfType(AdornRecipes.BREWING_TYPE.get())) { + BrewingEmiRecipe emiRecipe; + // TODO: Pattern matching + if (entry.value() instanceof ItemBrewingRecipe recipe) { + emiRecipe = new BrewingEmiRecipe(entry.id(), recipe); + } else if (entry.value() instanceof FluidBrewingRecipe recipe) { + emiRecipe = new BrewingEmiRecipe(entry.id(), recipe); + } else { + LOGGER.error("Unknown brewing recipe: {}", entry.value()); + continue; + } + + registry.addRecipe(emiRecipe); + } + + registry.addDragDropHandler(TradingStationScreen.class, new TradingStationDragDropHandler()); + } +} diff --git a/common/src/main/java/juuxel/adorn/compat/emi/BrewingEmiRecipe.java b/common/src/main/java/juuxel/adorn/compat/emi/BrewingEmiRecipe.java new file mode 100644 index 000000000..fef1e62af --- /dev/null +++ b/common/src/main/java/juuxel/adorn/compat/emi/BrewingEmiRecipe.java @@ -0,0 +1,110 @@ +package juuxel.adorn.compat.emi; + +import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import dev.emi.emi.api.widget.TankWidget; +import dev.emi.emi.api.widget.WidgetHolder; +import juuxel.adorn.AdornCommon; +import juuxel.adorn.block.entity.BrewerBlockEntity; +import juuxel.adorn.client.gui.screen.BrewerScreen; +import juuxel.adorn.item.AdornItems; +import juuxel.adorn.platform.FluidBridge; +import juuxel.adorn.recipe.FluidBrewingRecipe; +import juuxel.adorn.recipe.ItemBrewingRecipe; +import net.minecraft.util.Identifier; + +import java.util.List; + +public record BrewingEmiRecipe( + Identifier id, + EmiIngredient inputItem, + EmiIngredient firstItemIngredient, + EmiIngredient secondItemIngredient, + EmiIngredient fluidIngredient, + EmiStack result +) implements EmiRecipe { + private static final int PADDING = 0; + private static final int FLUID_SCALE_Z_OFFSET = 100; + private static final Identifier TEXTURE = AdornCommon.id("textures/gui/recipe_viewer/brewer_light.png"); + + public BrewingEmiRecipe(Identifier id, ItemBrewingRecipe recipe) { + this( + id, + EmiStack.of(AdornItems.INSTANCE.getMUG()), + EmiUtil.withRemainders(EmiIngredient.of(recipe.firstIngredient())), + EmiUtil.withRemainders(EmiIngredient.of(recipe.secondIngredient())), + EmiStack.EMPTY, + EmiStack.of(recipe.result()) + ); + } + + public BrewingEmiRecipe(Identifier id, FluidBrewingRecipe recipe) { + this( + id, + EmiStack.of(AdornItems.INSTANCE.getMUG()), + EmiUtil.withRemainders(EmiIngredient.of(recipe.firstIngredient())), + EmiUtil.withRemainders(EmiIngredient.of(recipe.secondIngredient())), + EmiUtil.emiIngredientOf(recipe.fluid()), + EmiStack.of(recipe.result()) + ); + } + + @Override + public EmiRecipeCategory getCategory() { + return AdornEmiPlugin.BREWER_CATEGORY; + } + + @Override + public Identifier getId() { + return id; + } + + @Override + public List getInputs() { + return List.of(inputItem, firstItemIngredient, secondItemIngredient, fluidIngredient); + } + + @Override + public List getOutputs() { + return List.of(result); + } + + @Override + public int getDisplayWidth() { + return 78 + 27 + 2 * PADDING; + } + + @Override + public int getDisplayHeight() { + return 61 + 2 * PADDING; + } + + @Override + public void addWidgets(WidgetHolder widgets) { + int leftX = PADDING; + int topY = PADDING; + widgets.addTexture(TEXTURE, leftX, topY, 105, 61, 49, 16); + widgets.addSlot(firstItemIngredient, leftX, topY).drawBack(false); + widgets.addSlot(secondItemIngredient, leftX + 60, topY).drawBack(false); + widgets.addSlot(result, leftX + 26, topY + 35).drawBack(false).recipeContext(this).large(true); + var capacity = BrewerBlockEntity.FLUID_CAPACITY_IN_BUCKETS * FluidBridge.get().getFluidUnit().getBucketVolume(); + widgets.add(new TankWidget(fluidIngredient, leftX + 87, topY, 18, BrewerScreen.FLUID_AREA_HEIGHT + 2, capacity).drawBack(false)); + + // Empty mug + widgets.addSlot(inputItem, leftX + 3, topY + 38).drawBack(false); + + // Fluid scale + widgets.addDrawable(leftX + 88, topY + 1, 16, BrewerScreen.FLUID_AREA_HEIGHT, (context, mouseX, mouseY, tickDelta) -> { + context.drawTexture(TEXTURE, 0, 0, FLUID_SCALE_Z_OFFSET, 154f, 17f, 16, BrewerScreen.FLUID_AREA_HEIGHT, 256, 256); + }); + + // Progress arrow + widgets.addDrawable(leftX + 35, topY + 8, 8, BrewerScreen.FLUID_AREA_HEIGHT, (context, mouseX, mouseY, tickDelta) -> { + float progressFraction = (System.currentTimeMillis() % 4000) / 4000f; + int height = Math.round(progressFraction * 25); + context.drawTexture(TEXTURE, 0, 0, 1, 176f, 0f, 8, height, 256, 256); + }); + } +} diff --git a/common/src/main/java/juuxel/adorn/compat/emi/EmiUtil.java b/common/src/main/java/juuxel/adorn/compat/emi/EmiUtil.java new file mode 100644 index 000000000..c9472d478 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/compat/emi/EmiUtil.java @@ -0,0 +1,34 @@ +package juuxel.adorn.compat.emi; + +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import juuxel.adorn.fluid.FluidIngredient; +import juuxel.adorn.fluid.FluidUnit; +import juuxel.adorn.platform.FluidBridge; +import net.minecraft.item.Item; + +public final class EmiUtil { + public static EmiIngredient emiIngredientOf(FluidIngredient ingredient) { + long amount = FluidUnit.convert(ingredient.amount(), ingredient.unit(), FluidBridge.get().getFluidUnit()); + return EmiIngredient.of( + ingredient.fluid() + .getFluids() + .stream() + .map(fluid -> EmiStack.of(fluid, ingredient.nbt(), amount)) + .toList() + ); + } + + public static EmiIngredient withRemainders(EmiIngredient ingredient) { + for (var stack : ingredient.getEmiStacks()) { + var item = stack.getKeyOfType(Item.class); + if (item == null) continue; + if (item.hasRecipeRemainder()) { + // TODO: Use stack-aware recipe remainders + stack.setRemainder(EmiStack.of(item.getRecipeRemainder())); + } + } + + return ingredient; + } +} diff --git a/common/src/main/java/juuxel/adorn/compat/emi/TradingStationDragDropHandler.java b/common/src/main/java/juuxel/adorn/compat/emi/TradingStationDragDropHandler.java new file mode 100644 index 000000000..04facc5ba --- /dev/null +++ b/common/src/main/java/juuxel/adorn/compat/emi/TradingStationDragDropHandler.java @@ -0,0 +1,35 @@ +package juuxel.adorn.compat.emi; + +import dev.emi.emi.api.EmiDragDropHandler; +import dev.emi.emi.api.stack.EmiIngredient; +import dev.emi.emi.api.stack.EmiStack; +import juuxel.adorn.client.gui.screen.TradingStationScreen; +import juuxel.adorn.menu.TradingStationMenu; +import net.minecraft.menu.Slot; + +import java.util.List; +import java.util.Optional; + +public final class TradingStationDragDropHandler implements EmiDragDropHandler { + @Override + public boolean dropStack(TradingStationScreen screen, EmiIngredient stack, int x, int y) { + var itemStack = single(stack.getEmiStacks()).map(EmiStack::getItemStack).orElse(null); + if (itemStack == null || itemStack.isEmpty() || !TradingStationMenu.isValidItem(itemStack)) return false; + + for (var slot : new Slot[] { screen.getMenu().getSellingSlot(), screen.getMenu().getPriceSlot() }) { + var slotX = slot.x + screen.getPanelX(); + var slotY = slot.y + screen.getPanelY(); + + if (slotX <= x && slotX < slotX + 16 && slotY <= y && y < slotY + 16) { + screen.updateTradeStack(slot, itemStack); + return true; + } + } + + return false; + } + + private static Optional single(List ts) { + return ts.size() == 1 ? Optional.of(ts.get(0)) : Optional.empty(); + } +} diff --git a/common/src/main/java/juuxel/adorn/fluid/FluidIngredient.java b/common/src/main/java/juuxel/adorn/fluid/FluidIngredient.java index 0fbfd7272..eae1a6972 100644 --- a/common/src/main/java/juuxel/adorn/fluid/FluidIngredient.java +++ b/common/src/main/java/juuxel/adorn/fluid/FluidIngredient.java @@ -4,7 +4,6 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Optional; @@ -45,7 +44,6 @@ public long getAmount() { return amount; } - @NotNull @Override public FluidUnit getUnit() { return unit; diff --git a/common/src/main/kotlin/juuxel/adorn/compat/emi/AdornEmiPlugin.kt b/common/src/main/kotlin/juuxel/adorn/compat/emi/AdornEmiPlugin.kt deleted file mode 100644 index 4b2dfbc38..000000000 --- a/common/src/main/kotlin/juuxel/adorn/compat/emi/AdornEmiPlugin.kt +++ /dev/null @@ -1,50 +0,0 @@ -package juuxel.adorn.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.EmiStack -import juuxel.adorn.AdornCommon -import juuxel.adorn.block.AdornBlocks -import juuxel.adorn.client.gui.screen.TradingStationScreen -import juuxel.adorn.recipe.AdornRecipes -import juuxel.adorn.recipe.FluidBrewingRecipe -import juuxel.adorn.recipe.ItemBrewingRecipe -import juuxel.adorn.util.logger - -@EmiEntrypoint -class AdornEmiPlugin : EmiPlugin { - override fun register(registry: EmiRegistry) { - registry.addCategory(BREWER_CATEGORY) - registry.addWorkstation(BREWER_CATEGORY, EmiStack.of(AdornBlocks.BREWER)) - - val recipeManager = registry.recipeManager - - for (entry in recipeManager.listAllOfType(AdornRecipes.BREWING_TYPE.get())) { - val emiRecipe = when (val recipe = entry.value) { - is ItemBrewingRecipe -> BrewingEmiRecipe(entry.id, recipe) - is FluidBrewingRecipe -> BrewingEmiRecipe(entry.id, recipe) - else -> { - LOGGER.error("Unknown brewing recipe: {}", recipe) - continue - } - } - - registry.addRecipe(emiRecipe) - } - - registry.addDragDropHandler(TradingStationScreen::class.java, TradingStationDragDropHandler) - } - - companion object { - private val LOGGER = logger() - - val BREWER_CATEGORY: EmiRecipeCategory = EmiRecipeCategory( - AdornCommon.id("brewer"), - EmiStack.of(AdornBlocks.BREWER), - EmiTexture(AdornCommon.id("textures/gui/recipe_viewer/brewer_light.png"), 240, 0, 16, 16) - ) - } -} diff --git a/common/src/main/kotlin/juuxel/adorn/compat/emi/BrewingEmiRecipe.kt b/common/src/main/kotlin/juuxel/adorn/compat/emi/BrewingEmiRecipe.kt deleted file mode 100644 index 9eb40d3bc..000000000 --- a/common/src/main/kotlin/juuxel/adorn/compat/emi/BrewingEmiRecipe.kt +++ /dev/null @@ -1,90 +0,0 @@ -package juuxel.adorn.compat.emi - -import dev.emi.emi.api.recipe.EmiRecipe -import dev.emi.emi.api.recipe.EmiRecipeCategory -import dev.emi.emi.api.stack.EmiIngredient -import dev.emi.emi.api.stack.EmiStack -import dev.emi.emi.api.widget.TankWidget -import dev.emi.emi.api.widget.WidgetHolder -import juuxel.adorn.AdornCommon -import juuxel.adorn.block.entity.BrewerBlockEntity -import juuxel.adorn.client.gui.screen.BrewerScreen -import juuxel.adorn.item.AdornItems -import juuxel.adorn.platform.FluidBridge -import juuxel.adorn.recipe.FluidBrewingRecipe -import juuxel.adorn.recipe.ItemBrewingRecipe -import net.minecraft.util.Identifier -import kotlin.math.roundToInt - -class BrewingEmiRecipe private constructor( - private val id: Identifier, - private val inputItem: EmiIngredient, - private val firstItemIngredient: EmiIngredient, - private val secondItemIngredient: EmiIngredient, - private val fluidIngredient: EmiIngredient, - private val result: EmiStack -) : EmiRecipe { - constructor(id: Identifier, recipe: ItemBrewingRecipe) : this( - id, - EmiStack.of(AdornItems.MUG), - EmiIngredient.of(recipe.firstIngredient).withRemainders(), - EmiIngredient.of(recipe.secondIngredient).withRemainders(), - EmiStack.EMPTY, - EmiStack.of(recipe.result) - ) - - constructor(id: Identifier, recipe: FluidBrewingRecipe) : this( - id, - EmiStack.of(AdornItems.MUG), - EmiIngredient.of(recipe.firstIngredient).withRemainders(), - EmiIngredient.of(recipe.secondIngredient).withRemainders(), - recipe.fluid.toEmiIngredient(), - EmiStack.of(recipe.result) - ) - - override fun getCategory(): EmiRecipeCategory = AdornEmiPlugin.BREWER_CATEGORY - override fun getId(): Identifier = id - - override fun getInputs() = listOf( - inputItem, - firstItemIngredient, - secondItemIngredient, - fluidIngredient, - ) - - override fun getOutputs() = listOf(result) - override fun getDisplayWidth(): Int = 78 + 27 + 2 * PADDING - override fun getDisplayHeight(): Int = 61 + 2 * PADDING - - override fun addWidgets(widgets: WidgetHolder) { - val leftX = PADDING - val topY = PADDING - widgets.addTexture(TEXTURE, leftX, topY, 105, 61, 49, 16) - widgets.addSlot(firstItemIngredient, leftX, topY).drawBack(false) - widgets.addSlot(secondItemIngredient, leftX + 60, topY).drawBack(false) - widgets.addSlot(result, leftX + 26, topY + 35).drawBack(false).recipeContext(this).large(true) - val capacity = BrewerBlockEntity.FLUID_CAPACITY_IN_BUCKETS * FluidBridge.get().fluidUnit.bucketVolume - widgets.add(TankWidget(fluidIngredient, leftX + 87, topY, 18, BrewerScreen.FLUID_AREA_HEIGHT + 2, capacity).drawBack(false)) - - // Empty mug - widgets.addSlot(inputItem, leftX + 3, topY + 38).drawBack(false) - - // Fluid scale - widgets.addDrawable(leftX + 88, topY + 1, 16, BrewerScreen.FLUID_AREA_HEIGHT) { context, _, _, _ -> - context.drawTexture(TEXTURE, 0, 0, FLUID_SCALE_Z_OFFSET, 154f, 17f, 16, BrewerScreen.FLUID_AREA_HEIGHT, 256, 256) - } - - // Progress arrow - widgets.addDrawable(leftX + 35, topY + 8, 8, BrewerScreen.FLUID_AREA_HEIGHT) { context, _, _, _ -> - val progressFraction = (System.currentTimeMillis() % 4000) / 4000.0 - val height = (progressFraction * 25).roundToInt() - context.drawTexture(TEXTURE, 0, 0, 1, 176f, 0f, 8, height, 256, 256) - } - } - - companion object { - private const val PADDING = 0 - private const val FLUID_SCALE_Z_OFFSET = 100 - private val TEXTURE = AdornCommon.id("textures/gui/recipe_viewer/brewer_light.png") - } -} diff --git a/common/src/main/kotlin/juuxel/adorn/compat/emi/Extensions.kt b/common/src/main/kotlin/juuxel/adorn/compat/emi/Extensions.kt deleted file mode 100644 index c696a7053..000000000 --- a/common/src/main/kotlin/juuxel/adorn/compat/emi/Extensions.kt +++ /dev/null @@ -1,25 +0,0 @@ -package juuxel.adorn.compat.emi - -import dev.emi.emi.api.stack.EmiIngredient -import dev.emi.emi.api.stack.EmiStack -import juuxel.adorn.fluid.FluidIngredient -import juuxel.adorn.fluid.FluidUnit -import juuxel.adorn.platform.FluidBridge -import net.minecraft.item.Item - -fun FluidIngredient.toEmiIngredient(): EmiIngredient { - val amount = FluidUnit.convert(amount, unit, FluidBridge.get().fluidUnit) - return EmiIngredient.of(fluid.getFluids().map { EmiStack.of(it, nbt, amount) }) -} - -fun EmiIngredient.withRemainders(): EmiIngredient { - for (stack in emiStacks) { - stack.getKeyOfType(Item::class.java)?.let { item -> - if (item.hasRecipeRemainder()) { - stack.remainder = EmiStack.of(item.recipeRemainder) - } - } - } - - return this -} diff --git a/common/src/main/kotlin/juuxel/adorn/compat/emi/TradingStationDragDropHandler.kt b/common/src/main/kotlin/juuxel/adorn/compat/emi/TradingStationDragDropHandler.kt deleted file mode 100644 index a39f3ba9a..000000000 --- a/common/src/main/kotlin/juuxel/adorn/compat/emi/TradingStationDragDropHandler.kt +++ /dev/null @@ -1,25 +0,0 @@ -package juuxel.adorn.compat.emi - -import dev.emi.emi.api.EmiDragDropHandler -import dev.emi.emi.api.stack.EmiIngredient -import juuxel.adorn.client.gui.screen.TradingStationScreen -import juuxel.adorn.menu.TradingStationMenu - -object TradingStationDragDropHandler : EmiDragDropHandler { - override fun dropStack(screen: TradingStationScreen, stack: EmiIngredient, x: Int, y: Int): Boolean { - val itemStack = stack.emiStacks.singleOrNull()?.itemStack ?: return false - if (itemStack.isEmpty || !TradingStationMenu.isValidItem(itemStack)) return false - - for (slot in arrayOf(screen.menu.sellingSlot, screen.menu.priceSlot)) { - val slotX = slot.x + screen.panelX - val slotY = slot.y + screen.panelY - - if (x in slotX until (slotX + 16) && y in slotY until (slotY + 16)) { - screen.updateTradeStack(slot, itemStack) - return true - } - } - - return false - } -}