refactor: Make use of generic crafting recipe

This commit is contained in:
Linnea Gräf
2025-05-09 19:03:27 +02:00
parent 44c24712b7
commit f925bd2a8d
6 changed files with 88 additions and 74 deletions

View File

@@ -1,5 +1,6 @@
package moe.nea.firmament.compat.rei
import io.github.moulberry.repo.data.NEUCraftingRecipe
import me.shedaniel.rei.api.client.plugins.REIClientPlugin
import me.shedaniel.rei.api.client.registry.category.CategoryRegistry
import me.shedaniel.rei.api.client.registry.display.DisplayRegistry
@@ -19,11 +20,12 @@ import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import net.minecraft.util.Identifier
import moe.nea.firmament.compat.rei.recipes.SBCraftingRecipe
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
import moe.nea.firmament.compat.rei.recipes.SBReforgeRecipe
import moe.nea.firmament.compat.rei.recipes.SBShopRecipe
import moe.nea.firmament.events.HandledScreenPushREIEvent
@@ -31,6 +33,7 @@ import moe.nea.firmament.features.inventory.CraftingOverlay
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.util.MC
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.guessRecipeId
@@ -52,19 +55,23 @@ class FirmamentReiPlugin : REIClientPlugin {
registry.register(TransferHandler { context ->
val screen = context.containerScreen
val display = context.display
if (display !is SBCraftingRecipe) return@TransferHandler TransferHandler.Result.createNotApplicable()
val neuItem = RepoManager.getNEUItem(SkyblockId(display.neuRecipe.output.itemId))
?: error("Could not find neu item ${display.neuRecipe.output.itemId} which is used in a recipe output")
if (display !is SBRecipe) return@TransferHandler TransferHandler.Result.createNotApplicable()
val recipe = display.neuRecipe
if (recipe !is NEUCraftingRecipe) return@TransferHandler TransferHandler.Result.createNotApplicable()
val neuItem = RepoManager.getNEUItem(SkyblockId(recipe.output.itemId))
?: error("Could not find neu item ${recipe.output.itemId} which is used in a recipe output")
val useSuperCraft = context.isStackedCrafting || RepoManager.Config.alwaysSuperCraft
if (neuItem.isVanilla && useSuperCraft) return@TransferHandler TransferHandler.Result.createFailed(Text.translatable(
"firmament.recipe.novanilla"))
var shouldReturn = true
if (context.isActuallyCrafting && !useSuperCraft) {
if (screen !is GenericContainerScreen || screen.title?.unformattedString != CraftingOverlay.CRAFTING_SCREEN_NAME) {
val craftingScreen = (screen as? GenericContainerScreen)
?.takeIf { it.title?.unformattedString == CraftingOverlay.CRAFTING_SCREEN_NAME }
if (craftingScreen == null) {
MC.sendCommand("craft")
shouldReturn = false
}
CraftingOverlay.setOverlay(screen as? GenericContainerScreen, display.neuRecipe)
CraftingOverlay.setOverlay(craftingScreen, recipe)
}
if (context.isActuallyCrafting && useSuperCraft) {
shouldReturn = false
@@ -75,8 +82,13 @@ 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),
)
override fun registerCategories(registry: CategoryRegistry) {
registry.add(SBCraftingRecipe.Category)
registry.add(generics)
registry.add(SBForgeRecipe.Category)
registry.add(SBMobDropRecipe.Category)
registry.add(SBKatRecipe.Category)
@@ -91,9 +103,9 @@ class FirmamentReiPlugin : REIClientPlugin {
}
override fun registerDisplays(registry: DisplayRegistry) {
registry.registerDisplayGenerator(
SBCraftingRecipe.Category.catIdentifier,
SkyblockCraftingRecipeDynamicGenerator)
generics.forEach {
it.registerDynamicGenerator(registry)
}
registry.registerDisplayGenerator(
SBReforgeRecipe.catIdentifier,
SBReforgeRecipe.DynamicGenerator

View File

@@ -1,6 +1,5 @@
package moe.nea.firmament.compat.rei
import io.github.moulberry.repo.data.NEUCraftingRecipe
import io.github.moulberry.repo.data.NEUForgeRecipe
import io.github.moulberry.repo.data.NEUKatUpgradeRecipe
import io.github.moulberry.repo.data.NEUMobDropRecipe
@@ -11,7 +10,6 @@ import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator
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.SBCraftingRecipe
import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe
import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe
import moe.nea.firmament.compat.rei.recipes.SBKatRecipe
@@ -22,9 +20,6 @@ import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.repo.SBItemStack
val SkyblockCraftingRecipeDynamicGenerator =
neuDisplayGenerator<SBCraftingRecipe, NEUCraftingRecipe> { SBCraftingRecipe(it) }
val SkyblockForgeRecipeDynamicGenerator =
neuDisplayGenerator<SBForgeRecipe, NEUForgeRecipe> { SBForgeRecipe(it) }
@@ -43,12 +38,16 @@ inline fun <D : Display, reified T : NEURecipe> neuDisplayGenerator(crossinline
neuDisplayGeneratorWithItem<D, T> { _, it -> mapper(it) }
inline fun <D : Display, reified T : NEURecipe> neuDisplayGeneratorWithItem(crossinline mapper: (SBItemStack, T) -> D) =
neuDisplayGeneratorWithItem(T::class.java, mapper)
inline fun <D : Display, T : NEURecipe> neuDisplayGeneratorWithItem(
filter: Class<T>,
crossinline mapper: (SBItemStack, T) -> D) =
object : DynamicDisplayGenerator<D> {
override fun getRecipeFor(entry: EntryStack<*>): Optional<List<D>> {
if (entry.type != SBItemEntryDefinition.type) return Optional.empty()
val item = entry.castValue<SBItemStack>()
val recipes = RepoManager.getRecipesFor(item.skyblockId)
val craftingRecipes = recipes.filterIsInstance<T>()
val craftingRecipes = recipes.filterIsInstance<T>(filter)
return Optional.of(craftingRecipes.map { mapper(item, it) })
}
@@ -60,7 +59,7 @@ inline fun <D : Display, reified T : NEURecipe> neuDisplayGeneratorWithItem(cros
if (entry.type != SBItemEntryDefinition.type) return Optional.empty()
val item = entry.castValue<SBItemStack>()
val recipes = RepoManager.getUsagesFor(item.skyblockId)
val craftingRecipes = recipes.filterIsInstance<T>()
val craftingRecipes = recipes.filterIsInstance<T>(filter)
return Optional.of(craftingRecipes.map { mapper(item, it) })
}
}

View File

@@ -0,0 +1,55 @@
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUCraftingRecipe
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.client.registry.display.DisplayRegistry
import me.shedaniel.rei.api.common.category.CategoryIdentifier
import me.shedaniel.rei.api.common.util.EntryStacks
import net.minecraft.text.Text
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>(
val renderer: GenericRecipeRenderer<T>,
) : DisplayCategory<GenericRecipe<T>> {
private val dynamicGenerator =
neuDisplayGeneratorWithItem<GenericRecipe<T>, T>(renderer.typ) { _, it -> GenericRecipe(it, categoryIdentifier) }
private val categoryIdentifier = CategoryIdentifier.of<GenericRecipe<T>>(renderer.identifier)
override fun getCategoryIdentifier(): CategoryIdentifier<GenericRecipe<T>> {
return categoryIdentifier
}
override fun getTitle(): Text? {
return renderer.title
}
override fun getIcon(): Renderer? {
return EntryStacks.of(renderer.icon)
}
override fun setupDisplay(display: GenericRecipe<T>, bounds: Rectangle): List<Widget> {
val layouter = REIRecipeLayouter()
layouter.container.add(Widgets.createRecipeBase(bounds))
renderer.render(display.neuRecipe, bounds, layouter)
return layouter.container
}
fun registerDynamicGenerator(registry: DisplayRegistry) {
registry.registerDisplayGenerator(categoryIdentifier, dynamicGenerator)
}
}
class GenericRecipe<T : NEUCraftingRecipe>(
override val neuRecipe: T,
val id: CategoryIdentifier<GenericRecipe<T>>
) : SBRecipe() {
override fun getCategoryIdentifier(): CategoryIdentifier<*>? {
return id
}
}

View File

@@ -1,56 +0,0 @@
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUCraftingRecipe
import io.github.moulberry.repo.data.NEUIngredient
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 me.shedaniel.rei.api.common.display.Display
import me.shedaniel.rei.api.common.display.DisplaySerializer
import me.shedaniel.rei.api.common.util.EntryStacks
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.repo.SBItemStack
class SBCraftingRecipe(override val neuRecipe: NEUCraftingRecipe) : SBRecipe() {
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.catIdentifier
object Category : DisplayCategory<SBCraftingRecipe> {
val catIdentifier = CategoryIdentifier.of<SBCraftingRecipe>(Firmament.MOD_ID, "crafting_recipe")
override fun getCategoryIdentifier(): CategoryIdentifier<out SBCraftingRecipe> = catIdentifier
override fun getTitle(): Text = Text.literal("SkyBlock Crafting")
override fun getIcon(): Renderer = SBItemEntryDefinition.getPassthrough(Blocks.CRAFTING_TABLE)
override fun setupDisplay(display: SBCraftingRecipe, bounds: Rectangle): List<Widget> {
val point = Point(bounds.centerX - 58, bounds.centerY - 27)
return buildList {
add(Widgets.createRecipeBase(bounds))
add(Widgets.createArrow(Point(point.x + 60, point.y + 18)))
add(Widgets.createResultSlotBackground(Point(point.x + 95, point.y + 19)))
for (i in 0 until 3) {
for (j in 0 until 3) {
val slot = Widgets.createSlot(Point(point.x + 1 + i * 18, point.y + 1 + j * 18)).markInput()
add(slot)
val item = display.neuRecipe.inputs[i + j * 3]
if (item == NEUIngredient.SENTINEL_EMPTY) continue
slot.entry(SBItemEntryDefinition.getEntry(item))
}
}
add(
Widgets.createSlot(Point(point.x + 95, point.y + 19))
.entry(SBItemEntryDefinition.getEntry(display.neuRecipe.output))
.disableBackground().markOutput()
)
}
}
}
}

View File

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

View File

@@ -12,7 +12,7 @@ import moe.nea.firmament.Firmament
import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.tr
class SBCraftingRecipeRenderer : GenericRecipeRenderer<NEUCraftingRecipe> {
object SBCraftingRecipeRenderer : GenericRecipeRenderer<NEUCraftingRecipe> {
override fun render(recipe: NEUCraftingRecipe, bounds: Rectangle, layouter: RecipeLayouter) {
val point = Point(bounds.centerX - 58, bounds.centerY - 27)
layouter.createArrow(point.x + 60, point.y + 18)
@@ -32,6 +32,9 @@ class SBCraftingRecipeRenderer : GenericRecipeRenderer<NEUCraftingRecipe> {
)
}
override val typ: Class<NEUCraftingRecipe>
get() = NEUCraftingRecipe::class.java
override fun getInputs(recipe: NEUCraftingRecipe): Collection<SBItemStack> {
return recipe.allInputs.mapNotNull { SBItemStack(it) }
}