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

View File

@@ -13,6 +13,8 @@ import moe.nea.firmament.repo.recipes.RecipeLayouter
class REIRecipeLayouter : RecipeLayouter { class REIRecipeLayouter : RecipeLayouter {
val container: MutableList<Widget> = mutableListOf() val container: MutableList<Widget> = mutableListOf()
fun <T: Widget> add(t: T): T = t.also(container::add)
override fun createItemSlot( override fun createItemSlot(
x: Int, x: Int,
y: Int, y: Int,
@@ -27,19 +29,22 @@ class REIRecipeLayouter : RecipeLayouter {
RecipeLayouter.SlotKind.SMALL_OUTPUT -> slot.markOutput() RecipeLayouter.SlotKind.SMALL_OUTPUT -> slot.markOutput()
RecipeLayouter.SlotKind.BIG_OUTPUT -> { RecipeLayouter.SlotKind.BIG_OUTPUT -> {
slot.markOutput().disableBackground() 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) { 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) { override fun createArrow(x: Int, y: Int) =
container.add(Widgets.createArrow(Point(x, y))) add(Widgets.createArrow(Point(x, y))).bounds
}
override fun createMoulConfig( override fun createMoulConfig(
x: Int, x: Int,
@@ -48,6 +53,10 @@ class REIRecipeLayouter : RecipeLayouter {
h: Int, h: Int,
component: GuiComponent 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.display.Display
import me.shedaniel.rei.api.common.entry.EntryStack import me.shedaniel.rei.api.common.entry.EntryStack
import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe 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.SBKatRecipe
import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe
import moe.nea.firmament.compat.rei.recipes.SBShopRecipe import moe.nea.firmament.compat.rei.recipes.SBShopRecipe
@@ -20,9 +19,6 @@ import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.repo.SBItemStack import moe.nea.firmament.repo.SBItemStack
val SkyblockForgeRecipeDynamicGenerator =
neuDisplayGenerator<SBForgeRecipe, NEUForgeRecipe> { SBForgeRecipe(it) }
val SkyblockMobDropRecipeDynamicGenerator = val SkyblockMobDropRecipeDynamicGenerator =
neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) } neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) }
val SkyblockShopRecipeDynamicGenerator = val SkyblockShopRecipeDynamicGenerator =

View File

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

View File

@@ -1,6 +1,8 @@
package moe.nea.firmament.repo.recipes package moe.nea.firmament.repo.recipes
import io.github.notenoughupdates.moulconfig.gui.GuiComponent import io.github.notenoughupdates.moulconfig.gui.GuiComponent
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.repo.SBItemStack import moe.nea.firmament.repo.SBItemStack
@@ -21,13 +23,16 @@ interface RecipeLayouter {
slotKind: SlotKind, slotKind: SlotKind,
) )
fun createTooltip(rectangle: Rectangle, label: Text)
fun createLabel( fun createLabel(
x: Int, y: Int, x: Int, y: Int,
text: Text 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 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
}