refactor: forge recipe as item list agnostic

This commit is contained in:
Linnea Gräf
2025-05-09 19:29:26 +02:00
parent f925bd2a8d
commit 62bca13bff
8 changed files with 114 additions and 91 deletions

View File

@@ -22,7 +22,6 @@ import net.minecraft.util.ActionResult
import net.minecraft.util.Identifier
import moe.nea.firmament.compat.rei.recipes.GenericREIRecipe
import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe
import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe
import moe.nea.firmament.compat.rei.recipes.SBKatRecipe
import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe
import moe.nea.firmament.compat.rei.recipes.SBRecipe
@@ -34,6 +33,7 @@ import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.repo.recipes.SBCraftingRecipeRenderer
import moe.nea.firmament.repo.recipes.SBForgeRecipeRenderer
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.guessRecipeId
@@ -84,12 +84,11 @@ class FirmamentReiPlugin : REIClientPlugin {
val generics = listOf<GenericREIRecipe<*>>( // Order matters: The order in here is the order in which they show up in REI
GenericREIRecipe(SBCraftingRecipeRenderer),
GenericREIRecipe(SBForgeRecipeRenderer),
)
override fun registerCategories(registry: CategoryRegistry) {
registry.add(generics)
registry.add(SBForgeRecipe.Category)
registry.add(SBMobDropRecipe.Category)
registry.add(SBKatRecipe.Category)
registry.add(SBReforgeRecipe.Category)
@@ -110,9 +109,6 @@ class FirmamentReiPlugin : REIClientPlugin {
SBReforgeRecipe.catIdentifier,
SBReforgeRecipe.DynamicGenerator
)
registry.registerDisplayGenerator(
SBForgeRecipe.Category.categoryIdentifier,
SkyblockForgeRecipeDynamicGenerator)
registry.registerDisplayGenerator(
SBMobDropRecipe.Category.categoryIdentifier,
SkyblockMobDropRecipeDynamicGenerator)

View File

@@ -13,6 +13,8 @@ import moe.nea.firmament.repo.recipes.RecipeLayouter
class REIRecipeLayouter : RecipeLayouter {
val container: MutableList<Widget> = mutableListOf()
fun <T: Widget> add(t: T): T = t.also(container::add)
override fun createItemSlot(
x: Int,
y: Int,
@@ -27,19 +29,22 @@ class REIRecipeLayouter : RecipeLayouter {
RecipeLayouter.SlotKind.SMALL_OUTPUT -> slot.markOutput()
RecipeLayouter.SlotKind.BIG_OUTPUT -> {
slot.markOutput().disableBackground()
container.add(Widgets.createResultSlotBackground(Point(x, y)))
add(Widgets.createResultSlotBackground(Point(x, y)))
}
}
container.add(slot)
add(slot)
}
override fun createTooltip(rectangle: Rectangle, label: Text) {
add(Widgets.createTooltip(rectangle, label))
}
override fun createLabel(x: Int, y: Int, text: Text) {
container.add(Widgets.createLabel(Point(x, y), text))
add(Widgets.createLabel(Point(x, y), text))
}
override fun createArrow(x: Int, y: Int) {
container.add(Widgets.createArrow(Point(x, y)))
}
override fun createArrow(x: Int, y: Int) =
add(Widgets.createArrow(Point(x, y))).bounds
override fun createMoulConfig(
x: Int,
@@ -48,6 +53,10 @@ class REIRecipeLayouter : RecipeLayouter {
h: Int,
component: GuiComponent
) {
container.add(wrapWidget(Rectangle(Point(x, y), Dimension(w, h)), component))
add(wrapWidget(Rectangle(Point(x, y), Dimension(w, h)), component))
}
override fun createFire(ingredientsCenter: Point, animationTicks: Int) {
add(Widgets.createBurningFire(ingredientsCenter).animationDurationTicks(animationTicks.toDouble()))
}
}

View File

@@ -11,7 +11,6 @@ import me.shedaniel.rei.api.client.view.ViewSearchBuilder
import me.shedaniel.rei.api.common.display.Display
import me.shedaniel.rei.api.common.entry.EntryStack
import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe
import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe
import moe.nea.firmament.compat.rei.recipes.SBKatRecipe
import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe
import moe.nea.firmament.compat.rei.recipes.SBShopRecipe
@@ -20,9 +19,6 @@ import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.repo.SBItemStack
val SkyblockForgeRecipeDynamicGenerator =
neuDisplayGenerator<SBForgeRecipe, NEUForgeRecipe> { SBForgeRecipe(it) }
val SkyblockMobDropRecipeDynamicGenerator =
neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) }
val SkyblockShopRecipeDynamicGenerator =

View File

@@ -1,6 +1,7 @@
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUCraftingRecipe
import io.github.moulberry.repo.data.NEURecipe
import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.client.gui.Renderer
import me.shedaniel.rei.api.client.gui.widgets.Widget
@@ -14,7 +15,7 @@ import moe.nea.firmament.compat.rei.REIRecipeLayouter
import moe.nea.firmament.compat.rei.neuDisplayGeneratorWithItem
import moe.nea.firmament.repo.recipes.GenericRecipeRenderer
class GenericREIRecipe<T : NEUCraftingRecipe>(
class GenericREIRecipe<T : NEURecipe>(
val renderer: GenericRecipeRenderer<T>,
) : DisplayCategory<GenericRecipe<T>> {
private val dynamicGenerator =
@@ -25,6 +26,10 @@ class GenericREIRecipe<T : NEUCraftingRecipe>(
return categoryIdentifier
}
override fun getDisplayHeight(): Int {
return renderer.displayHeight
}
override fun getTitle(): Text? {
return renderer.title
}
@@ -45,7 +50,7 @@ class GenericREIRecipe<T : NEUCraftingRecipe>(
}
}
class GenericRecipe<T : NEUCraftingRecipe>(
class GenericRecipe<T : NEURecipe>(
override val neuRecipe: T,
val id: CategoryIdentifier<GenericRecipe<T>>
) : SBRecipe() {

View File

@@ -1,71 +0,0 @@
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUForgeRecipe
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.client.gui.Renderer
import me.shedaniel.rei.api.client.gui.widgets.Widget
import me.shedaniel.rei.api.client.gui.widgets.Widgets
import me.shedaniel.rei.api.client.registry.display.DisplayCategory
import me.shedaniel.rei.api.common.category.CategoryIdentifier
import kotlin.math.cos
import kotlin.math.sin
import kotlin.time.Duration.Companion.seconds
import net.minecraft.block.Blocks
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.compat.rei.SBItemEntryDefinition
import moe.nea.firmament.compat.rei.plus
class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() {
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
object Category : DisplayCategory<SBForgeRecipe> {
override fun getCategoryIdentifier(): CategoryIdentifier<SBForgeRecipe> =
CategoryIdentifier.of(Firmament.MOD_ID, "forge_recipe")
override fun getTitle(): Text = Text.literal("Forge Recipes")
override fun getDisplayHeight(): Int {
return 104
}
override fun getIcon(): Renderer = SBItemEntryDefinition.getPassthrough(Blocks.ANVIL)
override fun setupDisplay(display: SBForgeRecipe, bounds: Rectangle): List<Widget> {
return buildList {
add(Widgets.createRecipeBase(bounds))
add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46)))
val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2))
add(arrow)
add(Widgets.createTooltip(arrow.bounds,
Text.stringifiedTranslatable("firmament.recipe.forge.time",
display.neuRecipe.duration.seconds)))
val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
add(Widgets.createBurningFire(ingredientsCenter).animationDurationTicks(25.0))
val count = display.neuRecipe.inputs.size
if (count == 1) {
add(
Widgets.createSlot(Point(ingredientsCenter.x, ingredientsCenter.y)).markInput()
.entry(SBItemEntryDefinition.getEntry(display.neuRecipe.inputs.single()))
)
} else {
display.neuRecipe.inputs.forEachIndexed { idx, ingredient ->
val rad = Math.PI * 2 * idx / count
add(
Widgets.createSlot(
Point(
cos(rad) * 30,
sin(rad) * 30,
) + ingredientsCenter
).markInput().entry(SBItemEntryDefinition.getEntry(ingredient))
)
}
}
add(
Widgets.createSlot(Point(bounds.minX + 124, bounds.minY + 46)).markOutput().disableBackground()
.entry(SBItemEntryDefinition.getEntry(display.neuRecipe.outputStack))
)
}
}
}
}

View File

@@ -16,5 +16,6 @@ interface GenericRecipeRenderer<T : NEURecipe> {
val title: Text
val identifier: Identifier
fun findAllRecipes(neuRepository: NEURepository): Iterable<T>
val displayHeight: Int get() = 66
val typ: Class<T>
}

View File

@@ -1,6 +1,8 @@
package moe.nea.firmament.repo.recipes
import io.github.notenoughupdates.moulconfig.gui.GuiComponent
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import net.minecraft.text.Text
import moe.nea.firmament.repo.SBItemStack
@@ -21,13 +23,16 @@ interface RecipeLayouter {
slotKind: SlotKind,
)
fun createTooltip(rectangle: Rectangle, label: Text)
fun createLabel(
x: Int, y: Int,
text: Text
)
fun createArrow(x: Int, y: Int)
fun createArrow(x: Int, y: Int): Rectangle
fun createMoulConfig(x: Int, y: Int, w: Int, h: Int, component: GuiComponent)
fun createFire(ingredientsCenter: Point, animationTicks: Int)
}

View File

@@ -0,0 +1,82 @@
package moe.nea.firmament.repo.recipes
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEUCraftingRecipe
import io.github.moulberry.repo.data.NEUForgeRecipe
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import kotlin.math.cos
import kotlin.math.sin
import kotlin.time.Duration.Companion.seconds
import net.minecraft.block.Blocks
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament
import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.tr
object SBForgeRecipeRenderer : GenericRecipeRenderer<NEUForgeRecipe> {
override fun render(
recipe: NEUForgeRecipe,
bounds: Rectangle,
layouter: RecipeLayouter
) {
val arrow = layouter.createArrow(bounds.minX + 90, bounds.minY + 54 - 18 / 2)
layouter.createTooltip(
arrow,
Text.stringifiedTranslatable(
"firmament.recipe.forge.time",
recipe.duration.seconds
)
)
val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
layouter.createFire(ingredientsCenter, 25)
val count = recipe.inputs.size
if (count == 1) {
layouter.createItemSlot(
ingredientsCenter.x, ingredientsCenter.y - 18,
SBItemStack(recipe.inputs.single()),
RecipeLayouter.SlotKind.SMALL_INPUT,
)
} else {
recipe.inputs.forEachIndexed { idx, ingredient ->
val rad = Math.PI * 2 * idx / count
layouter.createItemSlot(
(ingredientsCenter.x + cos(rad) * 30).toInt(), (ingredientsCenter.y + sin(rad) * 30).toInt(),
SBItemStack(ingredient),
RecipeLayouter.SlotKind.SMALL_INPUT,
)
}
}
layouter.createItemSlot(
bounds.minX + 124, bounds.minY + 46,
SBItemStack(recipe.outputStack),
RecipeLayouter.SlotKind.BIG_OUTPUT
)
}
override val displayHeight: Int
get() = 104
override fun getInputs(recipe: NEUForgeRecipe): Collection<SBItemStack> {
return recipe.inputs.mapNotNull { SBItemStack(it) }
}
override fun getOutputs(recipe: NEUForgeRecipe): Collection<SBItemStack> {
return listOfNotNull(SBItemStack(recipe.outputStack))
}
override val icon: ItemStack = ItemStack(Blocks.ANVIL)
override val title: Text = tr("firmament.category.forge", "Forge Recipes")
override val identifier: Identifier = Firmament.identifier("forge_recipe")
override fun findAllRecipes(neuRepository: NEURepository): Iterable<NEUForgeRecipe> {
// TODO: theres gotta be an index for these tbh.
return neuRepository.items.items.values.flatMap { it.recipes }.filterIsInstance<NEUForgeRecipe>()
}
override val typ: Class<NEUForgeRecipe>
get() = NEUForgeRecipe::class.java
}