package moe.nea.firmament.features.items.recipes import com.mojang.blaze3d.platform.InputConstants import io.github.moulberry.repo.IReloadable import io.github.moulberry.repo.NEURepository import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HandledScreenKeyPressedEvent import moe.nea.firmament.events.ReloadRegistrationEvent import moe.nea.firmament.keybindings.SavedKeyBinding import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.repo.SBItemStack import moe.nea.firmament.repo.recipes.GenericRecipeRenderer import moe.nea.firmament.repo.recipes.SBCraftingRecipeRenderer import moe.nea.firmament.repo.recipes.SBEssenceUpgradeRecipeRenderer import moe.nea.firmament.repo.recipes.SBForgeRecipeRenderer import moe.nea.firmament.repo.recipes.SBReforgeRecipeRenderer import moe.nea.firmament.util.MC import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.focusedItemStack object RecipeRegistry { val recipeTypes: List> = listOf( SBCraftingRecipeRenderer, SBForgeRecipeRenderer, SBReforgeRecipeRenderer, SBEssenceUpgradeRecipeRenderer, ) @Subscribe fun showUsages(event: HandledScreenKeyPressedEvent) { val provider = if (event.matches(SavedKeyBinding.keyWithoutMods(InputConstants.KEY_R))) { ::getRecipesFor } else if (event.matches(SavedKeyBinding.keyWithoutMods(InputConstants.KEY_U))) { ::getUsagesFor } else { return } val stack = event.screen.focusedItemStack ?: return val recipes = provider(SBItemStack(stack)) if (recipes.isEmpty()) return MC.screen = RecipeScreen(recipes.toList()) } object RecipeIndexes : IReloadable { private fun createIndexFor( neuRepository: NEURepository, recipeRenderer: GenericRecipeRenderer, outputs: Boolean, ): List>> { val indexer: (T) -> Collection = if (outputs) recipeRenderer::getOutputs else recipeRenderer::getInputs return recipeRenderer.findAllRecipes(neuRepository) .flatMap { val wrappedRecipe = RenderableRecipe(it, recipeRenderer, null) indexer(it).map { it.skyblockId to wrappedRecipe } } } fun createIndex(outputs: Boolean): MutableMap>> { val m: MutableMap>> = mutableMapOf() recipeTypes.forEach { renderer -> createIndexFor(RepoManager.neuRepo, renderer, outputs) .forEach { (stack, recipe) -> m.merge(stack, listOf(recipe)) { a, b -> a + b } } } return m } lateinit var recipesForIndex: Map>> lateinit var usagesForIndex: Map>> override fun reload(recipe: NEURepository) { recipesForIndex = createIndex(true) usagesForIndex = createIndex(false) } } @Subscribe fun onRepoBuild(event: ReloadRegistrationEvent) { event.repo.registerReloadListener(RecipeIndexes) } fun getRecipesFor(itemStack: SBItemStack): Set> { val recipes = LinkedHashSet>() recipeTypes.forEach { injectRecipesFor(it, recipes, itemStack, true) } recipes.addAll(RecipeIndexes.recipesForIndex[itemStack.skyblockId] ?: emptyList()) return recipes } fun getUsagesFor(itemStack: SBItemStack): Set> { val recipes = LinkedHashSet>() recipeTypes.forEach { injectRecipesFor(it, recipes, itemStack, false) } recipes.addAll(RecipeIndexes.usagesForIndex[itemStack.skyblockId] ?: emptyList()) return recipes } private fun injectRecipesFor( recipeRenderer: GenericRecipeRenderer, collector: MutableCollection>, relevantItem: SBItemStack, mustBeInOutputs: Boolean ) { collector.addAll( recipeRenderer.discoverExtraRecipes(RepoManager.neuRepo, relevantItem, mustBeInOutputs) .map { RenderableRecipe(it, recipeRenderer, relevantItem) } ) } }