Compare commits

...
Author SHA1 Message Date
Gertimoshka 4bac41d6d8 Added better support for JEI screen handling, allowing it to change tmm screen then autocompleting recipe 2026-06-25 18:16:42 +03:00
Gertimoshka bf4c211313 Adjustment and Sorting 2026-06-22 08:51:49 +03:00
Gertimoshka 91e4bbf54d Damn thats a lot of work, but TMMs TM Recipes for Recipe Viewers now are integrated 2026-06-22 01:05:01 +03:00
Gertimoshka a32769e8ed Merge 'main' into branch, fix conflicts 2026-06-21 09:27:11 +03:00
Gertimoshka f8a28d7d9f More work on TMM integration 2026-06-09 19:25:00 +03:00
Gertimoshka ea02c69ef4 TM recipes now shown even if ugly, even tells if you have it unlocked 2026-06-07 14:22:33 +03:00
Gertimoshka 40563d4165 Fixes and Preperations for TMM Recipes 2026-06-07 12:27:30 +03:00
Gertimoshka 0864be3a54 Merge branch 'main' into too-many-recipe-viewers 2026-06-07 09:13:06 +03:00
Gertimoshka 081ad66d22 I shall keep fixing merge conflicts till this get merged 2026-05-21 20:28:17 +03:00
Gertimoshka 9251c6ebf7 Cleanup 2026-05-14 21:33:46 +03:00
Gertimoshka f0247c764c Recipe Autofill for containers was very easy to make work trust :3 2026-05-14 21:29:55 +03:00
Gertimoshka 6116f3d3c3 Delete old textures 2026-05-14 08:29:30 +03:00
Gertimoshka d3e75af5e4 Merge branch 'main' into too-many-recipe-viewers and fix minor conflict 2026-05-14 08:26:06 +03:00
Gertimoshka ac6846a82f Minor Fixes 2026-05-04 19:47:54 +03:00
Gertimoshka ad16dab0d4 Merge branch 'main' into too-many-recipe-viewers 2026-05-03 20:32:36 +03:00
Gertimoshka 14ad76b672 Merge branch 'main' into too-many-recipe-viewers 2026-05-03 11:17:31 +03:00
Gertimoshka ab02895eed Neoforge REI side done 2026-05-03 10:55:08 +03:00
Gertimoshka 64e34df1ed Near Complete REI Implemintation 2026-05-02 17:50:03 +03:00
Gertimoshka 9cf65810ee Implemented Rest of the Categories,Cobblemon Brewing Recipes now work for JEI and EMI 2026-05-02 11:34:23 +03:00
Gertimoshka 99f8711063 Cooking Pot Recipes Viewing Reimplemented 2026-05-02 00:24:03 +03:00
Gertimoshka 433b351bcd Majour Base Implementation for Recipe Viewers 2026-05-01 22:33:26 +03:00
59 changed files with 1732 additions and 438 deletions
+6
View File
@@ -32,6 +32,8 @@ repositories {
maven(url = "https://api.modrinth.com/maven")
maven(url = "https://maven.neoforged.net/releases")
maven(url = "https://maven.gegy.dev")
maven(url = "https://maven.terraformersmc.com/")
maven(url = "https://maven.shedaniel.me")
mavenLocal()
}
@@ -62,6 +64,10 @@ dependencies {
// Unit Testing
testImplementation(libs.bundles.unitTesting)
modCompileOnlyApi(libs.emi)
modCompileOnlyApi(libs.rei.api)
modCompileOnlyApi(libs.rei.defaultplugin)
}
tasks.withType<Test> {
@@ -76,7 +76,7 @@ class TMMachineMenu(menuType: MenuType<*>, syncId: Int) : AbstractContainerMenu(
}
private fun initiateSlots() {
val startX = 15
val startX = 75
val startY = 144
val slotWidth = 18
val slotHeight = 18
@@ -160,7 +160,7 @@ class TMMachineMenu(menuType: MenuType<*>, syncId: Int) : AbstractContainerMenu(
}
class BlankTMSlot(container: Container, slot: Int, x: Int, y: Int) : Slot(container, slot, x, y) {
override fun mayPlace(stack: ItemStack): Boolean = super.mayPlace(stack) && (stack.item == CobblemonItems.BLANK_TM)
override fun mayPlace(stack: ItemStack): Boolean = super.mayPlace(stack) && ((stack.item == CobblemonItems.BLANK_TM) || stack.isEmpty)
}
override fun slotChanged(containerToSend: AbstractContainerMenu, dataSlotIndex: Int, stack: ItemStack) {
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.client.gui.cookingpot
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendToServer
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
@@ -16,8 +15,6 @@ import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.block.campfirepot.SeasoningSlot
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.COOKING_POT_COLOR_INDEX
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.IS_LID_OPEN_INDEX
import com.cobblemon.mod.common.integration.jei.CobblemonJeiPlugin
import com.cobblemon.mod.common.integration.jei.cooking.CampfirePotRecipeCategory
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
import com.cobblemon.mod.common.mixin.accessor.RecipeBookComponentAccessor
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
@@ -216,18 +213,6 @@ class CookingPotScreen(
override fun getRecipeBookComponent(): RecipeBookComponent = this.recipeBookComponent
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
val progressX = leftPos + 96
val progressY = topPos + 39
if (Cobblemon.implementation.isModInstalled("jei") &&
mouseX >= progressX && mouseX < progressX + COOK_PROGRESS_WIDTH &&
mouseY >= progressY && mouseY < progressY + COOK_PROGRESS_HEIGHT
) {
CobblemonJeiPlugin.jeiRuntime?.recipesGui?.showTypes(
listOf(CampfirePotRecipeCategory.RECIPE_TYPE)
)
return true
}
if (this.recipeBookComponent.mouseClicked(mouseX, mouseY, button)) {
this.focused = this.recipeBookComponent
@@ -248,28 +233,6 @@ class CookingPotScreen(
}
}
override fun renderTooltip(
guiGraphics: GuiGraphics,
mouseX: Int,
mouseY: Int
) {
val progressX = leftPos + 96
val progressY = topPos + 39
if (Cobblemon.implementation.isModInstalled("jei") &&
mouseX >= progressX && mouseX < progressX + COOK_PROGRESS_WIDTH &&
mouseY >= progressY && mouseY < progressY + COOK_PROGRESS_HEIGHT
) {
guiGraphics.renderTooltip(
this.font,
Component.translatable("jei.tooltip.show.recipes"),
mouseX,
mouseY
)
return
}
super.renderTooltip(guiGraphics, mouseX, mouseY)
}
private fun overrideRecipeBookFilterButton(filterButton: StateSwitchingButton) {
filterButton.initTextureValues(FILTER_BUTTON_SPRITES)
filterButton.setTooltip(
@@ -68,7 +68,7 @@ import kotlin.math.ceil
class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, title: Component) : AbstractContainerScreen<TMMachineMenu>(containerMenu, inventory, title) {
companion object {
const val HEIGHT = 226
const val WIDTH = 191
const val WIDTH = 251
const val HALF_SCALE = 0.5F
const val DISC_DIAMETER = 56
@@ -167,6 +167,8 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
super.init()
leftPos -= 60 / 2 // Adjust for the left slots
logoResource = getLogoResource(minecraft?.languageManager?.selected)
logoPosX = leftPos + 1
@@ -178,7 +180,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
partySlotList.clear()
CobblemonClient.storage.party.forEachIndexed { index, pokemon ->
partySlotList.add(TMPartySlotWidget(
pX = leftPos - 60,
pX = leftPos,
pY = topPos + 9 + ((TMPartySlotWidget.HEIGHT + 3) * index),
pokemon = pokemon,
onPress = {
@@ -208,7 +210,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
}
moveDescriptionWidget = MoveDescriptionWidget(
leftPos + 125,
leftPos + 185,
topPos + 42,
60,
34
@@ -216,7 +218,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
if (!children().contains(moveDescriptionWidget)) addRenderableWidget(moveDescriptionWidget)
typesScrollList = TypesScrollingWidget(
pX = leftPos + 6,
pX = leftPos + 66,
pY = topPos + 11,
setType = { type ->
sortType = type
@@ -227,7 +229,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
if (!children().contains(typesScrollList)) addRenderableWidget(typesScrollList)
movesScrollingList = MovesScrollingWidget(
pX = leftPos + 4,
pX = leftPos + 64,
pY = topPos + 29,
tmList,
setTM = { tm, clicked ->
@@ -241,7 +243,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
)
if (!children().contains(movesScrollingList)) addRenderableWidget(movesScrollingList)
moveSearchWidget = MoveSearchWidget(pX = leftPos + 16, pY = topPos + 13) {
moveSearchWidget = MoveSearchWidget(pX = leftPos + 76, pY = topPos + 13) {
if (::movesScrollingList.isInitialized && moveSearchWidget.isFocused) {
val input = moveSearchWidget.value
setMoveList(filter = if (input.isBlank()) null else input)
@@ -250,7 +252,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
if (!children().contains(moveSearchWidget)) addRenderableWidget(moveSearchWidget)
backButton = IconButton(
leftPos + 106F,
leftPos + 166F,
topPos + 1F,
20,
18,
@@ -261,7 +263,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
if (!children().contains(backButton)) addRenderableWidget(backButton)
selectedMoveButton = MoveSlotButton(
leftPos + 6,
leftPos + 66,
topPos + 6,
move = menu.currentlySelectedTM?.moveName,
pp = menu.currentlySelectedTM?.moveName?.pp ?: 0,
@@ -275,7 +277,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
}
if (!children().contains(selectedMoveButton)) addRenderableWidget(selectedMoveButton)
startButton = StartButton(leftPos + 5F, topPos + 35F) {
startButton = StartButton(leftPos + 65F, topPos + 35F) {
if (!(it as StartButton).disabled) {
menu.currentlySelectedTM?.let {
val burnActive = menu.containerData?.get(TMMachineBlockEntity.BURN_ACTIVE_INDEX) ?: 0
@@ -368,11 +370,11 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
logoPosY = logoPosY + (if (logoSlideDown) 1 else -1)
var borderHit = false
if (logoSlideRight && (logoPosX + (LOGO_WIDTH * HALF_SCALE).toInt()) >= (leftPos + SCREEN_SAVER_WIDTH + 1)) {
if (logoSlideRight && (logoPosX + (LOGO_WIDTH * HALF_SCALE).toInt()) >= (leftPos + SCREEN_SAVER_WIDTH + 61)) {
logoSlideRight = false
borderHit = true
}
if ((!logoSlideRight) && logoPosX <= (leftPos + 1)) {
if ((!logoSlideRight) && logoPosX <= (leftPos + 61)) {
logoSlideRight = true
borderHit = true
}
@@ -404,7 +406,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
private fun isBurnActive(): Boolean = (menu.containerData?.get(TMMachineBlockEntity.BURN_ACTIVE_INDEX) ?: 0) == 1
private fun setScreenFromMode(screen: Int) {
fun setScreenFromMode(screen: Int) {
mode = screen
when (mode) {
TYPE_SELECT_MODE -> {
@@ -426,7 +428,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
updateHeldStackMove()
}
private fun setMoveList(filter: String? = null, pokemon: Pokemon? = null) {
fun setMoveList(filter: String? = null, pokemon: Pokemon? = null) {
val filteredList = TechnicalMachine.filterTms(
search = filter,
type = sortType,
@@ -542,7 +544,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discBase,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -557,7 +559,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discReflectiveRotating,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -573,7 +575,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discRotating,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -588,7 +590,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discReflective,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -610,7 +612,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discOverlay,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -624,7 +626,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discBase,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -636,7 +638,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discReflectiveRotating,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -649,7 +651,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discRotating,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -661,7 +663,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discReflective,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -676,7 +678,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = discBorder,
x = leftPos + 32,
x = leftPos + 92,
y = topPos + 50,
width = DISC_DIAMETER,
height = DISC_DIAMETER,
@@ -690,7 +692,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = context.pose(),
texture = MovesWidget.movesPowerIconResource,
x = leftPos + 127.5,
x = leftPos + 187.5,
y = topPos + 7.5,
width = 5,
height = 5
@@ -699,7 +701,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = context.pose(),
texture = MovesWidget.movesAccuracyIconResource,
x = leftPos + 127.5,
x = leftPos + 187.5,
y = topPos + 19.5,
width = 5,
height = 5
@@ -708,7 +710,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = context.pose(),
texture = MovesWidget.movesEffectIconResource,
x = leftPos + 127.5,
x = leftPos + 187.5,
y = topPos + 31.5,
width = 5,
height = 5
@@ -717,7 +719,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
drawScaledText(
context = context,
text = lang("ui.power"),
x = leftPos + 134.5,
x = leftPos + 194.5,
y = topPos + 8,
shadow = true,
scale = HALF_SCALE
@@ -726,7 +728,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
drawScaledText(
context = context,
text = lang("ui.accuracy"),
x = leftPos + 134.5,
x = leftPos + 194.5,
y = topPos + 20,
shadow = true,
scale = HALF_SCALE
@@ -735,7 +737,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
drawScaledText(
context = context,
text = lang("ui.effect"),
x = leftPos + 134.5,
x = leftPos + 194.5,
y = topPos + 32,
shadow = true,
scale = HALF_SCALE
@@ -745,7 +747,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
drawScaledTextJustifiedRight(
context = context,
text = movePower,
x = leftPos + 183,
x = leftPos + 243,
y = topPos + 8,
shadow = true,
scale = HALF_SCALE
@@ -755,7 +757,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
drawScaledTextJustifiedRight(
context = context,
text = moveAccuracy,
x = leftPos + 183,
x = leftPos + 243,
y = topPos + 20,
shadow = true,
scale = HALF_SCALE
@@ -765,7 +767,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
drawScaledTextJustifiedRight(
context = context,
text = moveEffect,
x = leftPos + 183,
x = leftPos + 243,
y = topPos + 32,
shadow = true,
scale = HALF_SCALE
@@ -775,7 +777,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
val recipe = TechnicalMachines.moveToTM[moveTemplate]?.getClampedRecipe() ?: listOf()
// Render material cost
recipe.forEachIndexed { index, recipe ->
val itemX = (leftPos + 129 + (index * 18))
val itemX = (leftPos + 189 + (index * 18))
val itemY = (topPos + 90)
val stacks = recipe.ingredient.items
@@ -953,7 +955,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = screenSaver,
x = leftPos + 1,
x = leftPos + 61,
y = topPos + 1,
width = SCREEN_SAVER_WIDTH,
height = SCREEN_SAVER_HEIGHT,
@@ -977,7 +979,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = cobblemonResource("textures/white.png"),
x = leftPos + 1,
x = leftPos + 61,
y = scanPosY * 0.5,
width = SCREEN_SAVER_WIDTH,
height = 1,
@@ -988,15 +990,15 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
)
context.enableScissor(
leftPos + 1,
leftPos + 61,
topPos + 1,
leftPos + 1 + SCREEN_SAVER_WIDTH,
leftPos + 61 + SCREEN_SAVER_WIDTH,
topPos + 1 + SCREEN_SAVER_HEIGHT
)
blitk(
matrixStack = poseStack,
texture = scanLines,
x = leftPos + 1,
x = leftPos + 61,
y = topPos + 1 - scanLineOffsetY,
width = 118,
height = 114,
@@ -1007,7 +1009,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = poseStack,
texture = screenOverlay,
x = leftPos + 1,
x = leftPos + 61,
y = topPos + 1,
width = SCREEN_SAVER_WIDTH,
height = SCREEN_SAVER_HEIGHT,
@@ -1153,9 +1155,8 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
return super.keyPressed(keyCode, scanCode, modifiers)
}
override fun renderBackground(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {}
override fun renderBg(guiGraphics: GuiGraphics, partialTick: Float, mouseX: Int, mouseY: Int) {}
override fun renderTransparentBackground(guiGraphics: GuiGraphics) {}
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
super.renderTransparentBackground(graphics)
@@ -1164,16 +1165,16 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = matrices,
texture = baseResource,
x = leftPos,
x = leftPos + 60,
y = topPos,
width = WIDTH,
width = WIDTH - 60,
height = HEIGHT
)
blitk(
matrixStack = matrices,
texture = emptyDiscSlot,
x = leftPos + 105,
x = leftPos + 165,
y = topPos + 116,
width = 16,
height = 16
@@ -1185,7 +1186,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
context = graphics,
font = CobblemonResources.DEFAULT_LARGE,
text = label.bold(),
x = leftPos + 5,
x = leftPos + 65,
y = topPos + 1
)
@@ -1193,7 +1194,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = matrices,
texture = tmTray,
x = leftPos,
x = leftPos + 60,
y = topPos,
width = 120,
height = 112
@@ -1203,7 +1204,7 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
blitk(
matrixStack = matrices,
texture = CobblemonResources.WHITE,
x = leftPos + 33,
x = leftPos + 93,
y = topPos + 36,
width = burnProgressWidth,
height = 2
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.emi
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import dev.emi.emi.api.recipe.EmiRecipeCategory
import dev.emi.emi.api.render.EmiTexture
import net.minecraft.network.chat.Component
class CobblemonEmiCategory<T: RecipeViewerRecipe>(val provider: CobblemonEmiProvider<T>): EmiRecipeCategory(provider.originalProvider.id,
EmiTexture(provider.originalProvider.getIconResource(), 0, 0,
provider.originalProvider.getIconDimensions().x,
provider.originalProvider.getIconDimensions().y,
provider.originalProvider.getIconDimensions().x,
provider.originalProvider.getIconDimensions().y,
provider.originalProvider.getIconDimensions().x,
provider.originalProvider.getIconDimensions().y
)
) {
override fun getName(): Component = provider.originalProvider.getName()
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.emi
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.integration.emi.brewing.EmiCobblemonBrewingRecipe
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerComponentRegistry
import com.cobblemon.mod.common.integration.recipeviewer.brewing.CobblemonBrewingRecipeProvider
import dev.emi.emi.api.EmiEntrypoint
import dev.emi.emi.api.EmiPlugin
import dev.emi.emi.api.EmiRegistry
import dev.emi.emi.api.stack.Comparison
import dev.emi.emi.api.stack.EmiStack
@EmiEntrypoint
class CobblemonEmiPlugin: EmiPlugin {
companion object {
val emiProviders = RecipeViewerCategoryProvider.categoriesProviders.map {
CobblemonEmiProvider(it)
}
}
override fun register(registry: EmiRegistry) {
emiProviders.forEach {
it.register(registry)
}
// Cobblemon Brewing Recipes
CobblemonBrewingRecipeProvider.getRecipes().forEach { entry ->
registry.addRecipe(EmiCobblemonBrewingRecipe(entry.value, entry.id))
}
RecipeViewerComponentRegistry.register { item, component ->
registry.setDefaultComparison(EmiStack.of(item), Comparison.compareData { it.itemStack.get(component) })
}
}
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.emi
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import dev.emi.emi.api.EmiRegistry
import dev.emi.emi.api.stack.EmiStack
import net.minecraft.world.inventory.AbstractContainerMenu
class CobblemonEmiProvider<T: RecipeViewerRecipe>(val originalProvider: RecipeViewerCategoryProvider<T>) {
val category = CobblemonEmiCategory(this)
fun register(registry: EmiRegistry) {
registry.addCategory(category)
originalProvider.getWorkstations().forEach {
registry.addWorkstation(category, EmiStack.of(it))
}
originalProvider.getRecipes().forEach {
registry.addRecipe(CobblemonEmiRecipe(this, it))
}
originalProvider.recipeHandler().forEach {
registry.addRecipeHandler(it.getMenuType(), CobblemonEmiRecipeHandler(this, it))
}
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.emi
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.SlotType
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.SlotWidget
import dev.emi.emi.api.widget.WidgetHolder
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.crafting.Ingredient
class CobblemonEmiRecipe<T: RecipeViewerRecipe>(val provider: CobblemonEmiProvider<T>, val recipe: T): EmiRecipe {
override fun getCategory(): EmiRecipeCategory = provider.category
override fun getId(): ResourceLocation = recipe.getId()
override fun getDisplayWidth(): Int = provider.originalProvider.getWidth()
override fun getDisplayHeight(): Int = provider.originalProvider.getHeight()
private val ingredientHash = hashMapOf<Ingredient, EmiIngredient>() // This fixes the issue with some stuff
override fun getInputs(): List<EmiIngredient> {
return recipe.getInputs().map { ingredientHash.getOrPut(it.ingredient) { EmiIngredient.of(it.ingredient, it.count.toLong()) } }
}
override fun getOutputs(): List<EmiStack?> {
return recipe.getOutputs().map { EmiStack.of(it) }
}
override fun addWidgets(widgets: WidgetHolder) {
widgets.add(CobblemonEmiSimpleWidget(provider, recipe))
recipe.getSlots().forEach {
val ingredient = ingredientHash.getOrPut(it.ingredient.ingredient) { EmiIngredient.of(it.ingredient.ingredient, it.ingredient.count.toLong()) }
val emiSlot = SlotWidget(ingredient, it.x - 1, it.y - 1) //X, Y coordinate system slightly offset
emiSlot.drawBack(false)
if (it.type == SlotType.OUTPUT) emiSlot.recipeContext(this)
widgets.add(emiSlot)
}
}
override fun supportsRecipeTree(): Boolean = recipe.supportsRecipeTree()
override fun getCatalysts(): List<EmiIngredient> {
return recipe.getOptionalInputs().map { EmiIngredient.of(it.ingredient) }
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.emi
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import dev.emi.emi.api.recipe.EmiRecipe
import dev.emi.emi.api.recipe.handler.EmiCraftContext
import dev.emi.emi.api.recipe.handler.StandardRecipeHandler
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.Slot
class CobblemonEmiRecipeHandler<E: AbstractContainerMenu, R: RecipeViewerRecipe>(val provider: CobblemonEmiProvider<*>, val originalHandler: RecipeViewerRecipeHandler<R, E>): StandardRecipeHandler<E> {
override fun getCraftingSlots(menu: E): List<Slot> {
return originalHandler.getInputSlots(menu)
}
override fun getInputSources(menu: E): List<Slot> {
val theList = originalHandler.getInventorySlots(menu).toMutableList()
theList.addAll(originalHandler.getInputSlots(menu))
return theList
}
override fun supportsRecipe(recipe: EmiRecipe): Boolean {
return recipe.category == provider.category
}
override fun canCraft(recipe: EmiRecipe?, context: EmiCraftContext<E?>?): Boolean {
return super.canCraft(recipe, context) && (recipe as? CobblemonEmiRecipe<R>)?.let { originalHandler.isApplicable(it.recipe) } ?: false
}
override fun craft(recipe: EmiRecipe, context: EmiCraftContext<E>): Boolean {
(recipe as? CobblemonEmiRecipe<R>)?.let {
originalHandler.additionalHandle(recipe.recipe, context.screen.menu, context.screen)
}
return super.craft(recipe, context)
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.emi
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import dev.emi.emi.api.widget.Bounds
import dev.emi.emi.api.widget.Widget
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
class CobblemonEmiSimpleWidget<T: RecipeViewerRecipe>(val provider: CobblemonEmiProvider<T>, val recipe: T): Widget() {
override fun getBounds(): Bounds {
val original = provider.originalProvider
return Bounds(0, 0, original.getWidth(), original.getHeight())
}
override fun render(draw: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
val realDelta = Minecraft.getInstance().timer.realtimeDeltaTicks
recipe.renderRecipe( draw, mouseX, mouseY, realDelta)
}
}
@@ -0,0 +1,64 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.emi.brewing
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe
import dev.emi.emi.EmiPort
import dev.emi.emi.api.recipe.EmiRecipe
import dev.emi.emi.api.recipe.EmiRecipeCategory
import dev.emi.emi.api.recipe.VanillaEmiRecipeCategories
import dev.emi.emi.api.stack.EmiIngredient
import dev.emi.emi.api.stack.EmiStack
import dev.emi.emi.api.widget.WidgetHolder
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Items
class EmiCobblemonBrewingRecipe(val recipe: BrewingStandRecipe, val theId: ResourceLocation): EmiRecipe {
//I would have loved to use the base recipe one, but it just has 1 little caveat, input is an EmiStack, this is basically 99% recreation without that issue
private val input = EmiIngredient.of(recipe.input)
private val bottle = EmiIngredient.of(recipe.bottle)
private val output = EmiStack.of(recipe.result)
override fun getCategory(): EmiRecipeCategory = VanillaEmiRecipeCategories.BREWING
override fun getId(): ResourceLocation = theId
override fun getDisplayWidth(): Int = 120
override fun getDisplayHeight(): Int = 61
override fun getInputs(): List<EmiIngredient> {
return listOf(
bottle.copy().setAmount(3),
input
)
}
override fun getOutputs(): List<EmiStack> {
return listOf(
output.copy().setAmount(3)
)
}
override fun addWidgets(widgets: WidgetHolder) {
widgets.addTexture(BACKGROUND, 0, 0, 103, 61, 16, 14)
widgets.addAnimatedTexture(BACKGROUND, 81, 2, 9, 28, 176, 0, 1000 * 20, false, false, false).tooltip { mx, my ->
listOf(ClientTooltipComponent.create(EmiPort.ordered(EmiPort.translatable("emi.cooking.time", 20))))
}
widgets.addAnimatedTexture(BACKGROUND, 47, 0, 12, 29, 185, 0, 700, false, true, false)
widgets.addSlot(BLAZE_POWDER, 0, 2).drawBack(false)
widgets.addSlot(bottle, 39, 36).drawBack(false)
widgets.addSlot(input, 62, 2).drawBack(false)
widgets.addSlot(output, 85, 36).drawBack(false).recipeContext(this)
}
companion object {
private val BLAZE_POWDER = EmiStack.of(Items.BLAZE_POWDER)
private val BACKGROUND = EmiPort.id("minecraft", "textures/gui/container/brewing_stand.png")
}
}
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.SlotType
import mezz.jei.api.constants.VanillaTypes
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder
import mezz.jei.api.gui.builder.IRecipeSlotBuilder
import mezz.jei.api.gui.drawable.IDrawable
import mezz.jei.api.gui.ingredient.IRecipeSlotsView
import mezz.jei.api.recipe.IFocusGroup
import mezz.jei.api.recipe.RecipeIngredientRole
import mezz.jei.api.recipe.RecipeType
import mezz.jei.api.recipe.category.IRecipeCategory
import mezz.jei.api.registration.IRecipeCategoryRegistration
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
class CobblemonJeiCategory<T: RecipeViewerRecipe>(private val registration: IRecipeCategoryRegistration, val categoryProvider: CobblemonJeiProvider<T>):
IRecipeCategory<T> {
private val icon: IDrawable
init {
val guiHelper = registration.jeiHelpers.guiHelper
val dimensions = categoryProvider.originalProvider.getIconDimensions()
icon = guiHelper.drawableBuilder(categoryProvider.originalProvider.getIconResource(), 0, 0,
dimensions.x, dimensions.y)
.setTextureSize(dimensions.x, dimensions.y)
.build()
}
override fun getIcon(): IDrawable = icon
override fun getRecipeType(): RecipeType<T> = categoryProvider.recipeType
override fun getTitle(): Component = categoryProvider.originalProvider.getName()
override fun getWidth(): Int = categoryProvider.originalProvider.getWidth()
override fun getHeight(): Int = categoryProvider.originalProvider.getHeight()
override fun setRecipe(builder: IRecipeLayoutBuilder, recipe: T, focuses: IFocusGroup) {
recipe.getSlots().forEach { slot ->
val jeiSlot: IRecipeSlotBuilder = builder.addSlot(when (slot.type) {
SlotType.INPUT -> RecipeIngredientRole.INPUT
SlotType.OUTPUT -> RecipeIngredientRole.OUTPUT
SlotType.CATALYST -> RecipeIngredientRole.CATALYST
}, slot.x, slot.y)
val items = slot.ingredient.ingredient.items.map { it.copyWithCount(slot.ingredient.count) }
jeiSlot.addIngredients(VanillaTypes.ITEM_STACK, items)
}
}
override fun draw(
recipe: T,
recipeSlotsView: IRecipeSlotsView,
guiGraphics: GuiGraphics,
mouseX: Double,
mouseY: Double
) {
val delta = Minecraft.getInstance().timer.realtimeDeltaTicks
recipe.renderRecipe( guiGraphics, mouseX.toInt(), mouseY.toInt(), delta)
}
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei
import mezz.jei.api.ingredients.subtypes.ISubtypeInterpreter
import mezz.jei.api.ingredients.subtypes.UidContext
import net.minecraft.core.component.DataComponentType
import net.minecraft.world.item.ItemStack
class CobblemonJeiComponentComparator(val component: DataComponentType<*>): ISubtypeInterpreter<ItemStack> {
override fun getSubtypeData(ingredient: ItemStack, context: UidContext): Any? {
return ingredient.get(component)
}
override fun getLegacyStringSubtypeInfo(ingredient: ItemStack, context: UidContext): String = ""
}
@@ -8,54 +8,71 @@
package com.cobblemon.mod.common.integration.jei
import com.cobblemon.mod.common.integration.jei.berry.BerryMutationProvider
import com.cobblemon.mod.common.integration.jei.brewing.BrewingStandJeiProvider
import com.cobblemon.mod.common.integration.jei.cooking.CampfirePotJeiProvider
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.integration.jei.brewing.JeiBrewingStandRecipe
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerComponentRegistry
import com.cobblemon.mod.common.integration.recipeviewer.brewing.CobblemonBrewingRecipeProvider
import com.cobblemon.mod.common.util.cobblemonResource
import mezz.jei.api.IModPlugin
import mezz.jei.api.JeiPlugin
import mezz.jei.api.constants.RecipeTypes
import mezz.jei.api.registration.IGuiHandlerRegistration
import mezz.jei.api.registration.IRecipeCatalystRegistration
import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IRecipeRegistration
import mezz.jei.api.runtime.IJeiRuntime
import mezz.jei.api.registration.IRecipeTransferRegistration
import mezz.jei.api.registration.ISubtypeRegistration
import net.minecraft.resources.ResourceLocation
@JeiPlugin
class CobblemonJeiPlugin : IModPlugin {
private val jeiProviders: Set<CobblemonJeiProvider> = setOf(
BerryMutationProvider(),
CampfirePotJeiProvider(),
BrewingStandJeiProvider()
)
override fun getPluginUid(): ResourceLocation {
return ID
}
override fun registerCategories(registration: IRecipeCategoryRegistration) {
jeiProviders.forEach {
it.registerCategory(registration)
}
jeiProviders.forEach { it.registerCategory(registration) }
}
override fun registerRecipes(registration: IRecipeRegistration) {
jeiProviders.forEach {
it.registerRecipes(registration)
jeiProviders.forEach { it.registerRecipes(registration) }
// Cobblemon Brewing Recipes
val jeiRecipes = CobblemonBrewingRecipeProvider.getRecipes().map { entry ->
JeiBrewingStandRecipe(entry.value, entry.id)
}
registration.addRecipes(RecipeTypes.BREWING, jeiRecipes)
}
override fun registerRecipeCatalysts(registration: IRecipeCatalystRegistration) {
jeiProviders.forEach { it.registerRecipeCatalsysts(registration) }
}
override fun registerGuiHandlers(registration: IGuiHandlerRegistration) {
jeiProviders.forEach {
it.registerRecipeCatalsysts(registration)
it.registerGuiHandlers(registration)
}
}
override fun onRuntimeAvailable(jeiRuntime: IJeiRuntime) {
CobblemonJeiPlugin.jeiRuntime = jeiRuntime
override fun registerRecipeTransferHandlers(registration: IRecipeTransferRegistration) {
jeiProviders.forEach {
it.registerRecipeTransferHandlers(registration)
}
}
override fun registerItemSubtypes(registration: ISubtypeRegistration) {
RecipeViewerComponentRegistry.register { item, component ->
registration.registerSubtypeInterpreter(item, CobblemonJeiComponentComparator(component))
}
}
companion object {
var jeiRuntime: IJeiRuntime? = null
private val jeiProviders = RecipeViewerCategoryProvider.categoriesProviders.map {
CobblemonJeiProvider(it)
}
val ID = cobblemonResource("jei_plugin")
}
}
@@ -8,15 +8,40 @@
package com.cobblemon.mod.common.integration.jei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import mezz.jei.api.recipe.RecipeType
import mezz.jei.api.registration.IGuiHandlerRegistration
import mezz.jei.api.registration.IRecipeCatalystRegistration
import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IRecipeRegistration
import mezz.jei.api.registration.IRecipeTransferRegistration
/**
*
*/
interface CobblemonJeiProvider {
fun registerCategory(registration: IRecipeCategoryRegistration)
fun registerRecipes(registration: IRecipeRegistration)
fun registerRecipeCatalsysts(registration: IRecipeCatalystRegistration)
}
class CobblemonJeiProvider<T: RecipeViewerRecipe>(val originalProvider: RecipeViewerCategoryProvider<T>) {
val recipeType: RecipeType<T> =
RecipeType<T>.create(originalProvider.id.namespace, originalProvider.id.path, originalProvider.recipeClass)
fun registerCategory(registration: IRecipeCategoryRegistration) {
registration.addRecipeCategories(CobblemonJeiCategory(registration, this))
}
fun registerRecipes(registration: IRecipeRegistration) {
registration.addRecipes(recipeType, originalProvider.getRecipes())
}
fun registerRecipeCatalsysts(registration: IRecipeCatalystRegistration) {
originalProvider.getWorkstations().forEach {
registration.addRecipeCatalyst(it, recipeType)
}
}
fun registerGuiHandlers(registration: IGuiHandlerRegistration) {
originalProvider.getClickArea()?.let { registration.addRecipeClickArea(it.containerScreen, it.x, it.y, it.width, it.height, recipeType) }
}
fun registerRecipeTransferHandlers(registration: IRecipeTransferRegistration) {
originalProvider.recipeHandler().forEach {
registration.addRecipeTransferHandler(CobblemonJeiRecipeHandler(this, it, registration), recipeType)
}
}
}
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import mezz.jei.api.gui.ingredient.IRecipeSlotsView
import mezz.jei.api.recipe.RecipeType
import mezz.jei.api.recipe.transfer.IRecipeTransferError
import mezz.jei.api.recipe.transfer.IRecipeTransferHandler
import mezz.jei.api.registration.IRecipeTransferRegistration
import mezz.jei.api.runtime.IRecipesGui
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.MenuType
import java.util.Optional
class CobblemonJeiRecipeHandler<E: AbstractContainerMenu, R: RecipeViewerRecipe>(val provider: CobblemonJeiProvider<R>, val originalHandler: RecipeViewerRecipeHandler<R, E>, registry: IRecipeTransferRegistration): IRecipeTransferHandler<E, R> {
override fun getContainerClass(): Class<out E> = originalHandler.getMenuClass()
override fun getMenuType(): Optional<MenuType<E>> = Optional.of(originalHandler.getMenuType())
override fun getRecipeType(): RecipeType<R> = provider.recipeType
val recipeInfoHandler = registry.transferHelper.createUnregisteredRecipeTransferHandler(CobblemonJeiRecipeInfo(provider, originalHandler))
override fun transferRecipe(
container: E,
recipe: R,
recipeSlots: IRecipeSlotsView,
player: Player,
maxTransfer: Boolean,
doTransfer: Boolean
): IRecipeTransferError? {
if (doTransfer) {
val screen = Minecraft.getInstance().screen
val containerScreen = when (screen) {
is IRecipesGui -> if (screen.parentScreen.isPresent) screen.parentScreen.get() as? AbstractContainerScreen<E> else null
is AbstractContainerScreen<*> -> screen as? AbstractContainerScreen<E>
else -> null
}
originalHandler.additionalHandle(recipe, container, containerScreen)
}
return recipeInfoHandler.transferRecipe(container, recipe, recipeSlots, player, maxTransfer, doTransfer)
}
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import mezz.jei.api.recipe.RecipeType
import mezz.jei.api.recipe.transfer.IRecipeTransferInfo
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.inventory.Slot
import java.util.Optional
class CobblemonJeiRecipeInfo<E: AbstractContainerMenu, R: RecipeViewerRecipe>(val provider: CobblemonJeiProvider<R>, val originalHandler: RecipeViewerRecipeHandler<R, E>): IRecipeTransferInfo<E, R> {
override fun getContainerClass(): Class<out E> = originalHandler.getMenuClass()
override fun getMenuType(): Optional<MenuType<E>> = Optional.of(originalHandler.getMenuType())
override fun getRecipeType(): RecipeType<R> = provider.recipeType
override fun getRecipeSlots(container: E, recipe: R): List<Slot> {
return originalHandler.getInputSlots(container)
}
override fun getInventorySlots(container: E, recipe: R): List<Slot> {
return originalHandler.getInventorySlots(container)
}
override fun canHandle(container: E, recipe: R): Boolean {
return originalHandler.isApplicable(recipe)
}
}
@@ -1,42 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei.berry
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.integration.jei.CobblemonJeiProvider
import com.cobblemon.mod.common.item.berry.BerryItem
import mezz.jei.api.registration.IRecipeCatalystRegistration
import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IRecipeRegistration
class BerryMutationProvider : CobblemonJeiProvider {
override fun registerCategory(registration: IRecipeCategoryRegistration) {
registration.addRecipeCategories(BerryRecipeCategory(registration))
}
override fun registerRecipes(registration: IRecipeRegistration) {
val berryList = CobblemonItems.berries().map { it.value }
val berryMutations = mutableSetOf<Triple<BerryItem, BerryItem, BerryItem>>()
berryList.forEach {berry ->
for (mut in berry.berry()?.mutations?.entries ?: emptySet()) {
val berryTwo = CobblemonItems.berries()[mut.key] ?: continue
val berryThree = CobblemonItems.berries()[mut.value] ?: continue
val mutation = Triple(berry, berryTwo, berryThree)
val altMutation = Triple(berryTwo, berry, berryThree)
if (!(berryMutations.contains(mutation) || berryMutations.contains(altMutation))) {
berryMutations.add(mutation)
}
}
}
val berryMutationRecipes = berryMutations.map { BerryMutationRecipe(it.first, it.second, it.third) }
registration.addRecipes(BerryRecipeCategory.RECIPE_TYPE, berryMutationRecipes)
}
override fun registerRecipeCatalsysts(registration: IRecipeCatalystRegistration) { }
}
@@ -1,20 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei.berry
import com.cobblemon.mod.common.item.berry.BerryItem
//Dont make these ItemStacks, they do not have consistent hash codes, breaks stuff
data class BerryMutationRecipe(
val berryOne: BerryItem,
val berryTwo: BerryItem,
val berryResult: BerryItem
) {
}
@@ -1,61 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei.berry
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.util.cobblemonResource
import mezz.jei.api.constants.ModIds
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder
import mezz.jei.api.gui.drawable.IDrawable
import mezz.jei.api.recipe.IFocusGroup
import mezz.jei.api.recipe.RecipeIngredientRole
import mezz.jei.api.recipe.RecipeType
import mezz.jei.api.recipe.category.IRecipeCategory
import mezz.jei.api.registration.IRecipeCategoryRegistration
import net.minecraft.network.chat.Component
import net.minecraft.world.item.crafting.Ingredient
class BerryRecipeCategory(private val registration: IRecipeCategoryRegistration) : IRecipeCategory<BerryMutationRecipe> {
private var background: IDrawable
private var icon: IDrawable
init {
val guiHelper = registration.jeiHelpers.guiHelper
background = guiHelper.createDrawable(GUI_TEXTURE_ID, 0, 0, WIDTH, HEIGHT)
icon = guiHelper.createDrawableItemStack(CobblemonItems.SURPRISE_MULCH.defaultInstance)
}
override fun getRecipeType(): RecipeType<BerryMutationRecipe> {
return RECIPE_TYPE
}
override fun getTitle(): Component {
return Component.literal("Berry Mutation")
}
override fun getBackground(): IDrawable {
return background
}
override fun getIcon(): IDrawable {
return icon
}
override fun setRecipe(p0: IRecipeLayoutBuilder, p1: BerryMutationRecipe, p2: IFocusGroup) {
//These magic numbers are where the items should be positioned on the gui texture
p0.addSlot(RecipeIngredientRole.INPUT, 1, 1).addIngredients(Ingredient.of(p1.berryOne.defaultInstance))
p0.addSlot(RecipeIngredientRole.INPUT, 50, 1).addIngredients(Ingredient.of(p1.berryTwo.defaultInstance))
p0.addSlot(RecipeIngredientRole.OUTPUT, 108, 1).addIngredients(Ingredient.of(p1.berryResult.defaultInstance))
}
companion object {
val RECIPE_TYPE = RecipeType.create("cobblemon", "berry_recipe", BerryMutationRecipe::class.java)!!
val GUI_TEXTURE_ID = cobblemonResource("textures/gui/jei/berry_mutation.png")
const val WIDTH = 124
const val HEIGHT = 17
}
}
@@ -1,37 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei.brewing
import com.cobblemon.mod.common.CobblemonRecipeTypes
import com.cobblemon.mod.common.integration.jei.CobblemonJeiProvider
import mezz.jei.api.constants.RecipeTypes
import mezz.jei.api.registration.IRecipeCatalystRegistration
import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IRecipeRegistration
import net.minecraft.client.Minecraft
class BrewingStandJeiProvider : CobblemonJeiProvider {
override fun registerCategory(registration: IRecipeCategoryRegistration) {
}
override fun registerRecipes(registration: IRecipeRegistration) {
val recipeManger =
Minecraft.getInstance().level?.recipeManager ?: throw IllegalStateException("Recipe manager not found")
val allBrewingRecipes = recipeManger.getAllRecipesFor(CobblemonRecipeTypes.BREWING_STAND)
val jeiRecipes = allBrewingRecipes.map { entry ->
JeiBrewingStandRecipe(entry.value, entry.id)
}
registration.addRecipes(RecipeTypes.BREWING, jeiRecipes)
}
override fun registerRecipeCatalsysts(registration: IRecipeCatalystRegistration) { }
}
@@ -1,39 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei.cooking
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonRecipeTypes
import com.cobblemon.mod.common.integration.jei.CobblemonJeiProvider
import mezz.jei.api.registration.IRecipeCatalystRegistration
import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IRecipeRegistration
import net.minecraft.client.Minecraft
class CampfirePotJeiProvider : CobblemonJeiProvider {
override fun registerCategory(registration: IRecipeCategoryRegistration) {
registration.addRecipeCategories(CampfirePotRecipeCategory(registration))
}
override fun registerRecipes(registration: IRecipeRegistration) {
val recipeManger = Minecraft.getInstance().level?.recipeManager ?: throw IllegalStateException("Recipe manager not found")
val shapelessRecipes = recipeManger.getAllRecipesFor(CobblemonRecipeTypes.COOKING_POT_SHAPELESS).map { it.value }
val cookingRecipes = recipeManger.getAllRecipesFor(CobblemonRecipeTypes.COOKING_POT_COOKING).map { it.value }
registration.addRecipes(CampfirePotRecipeCategory.RECIPE_TYPE, shapelessRecipes)
registration.addRecipes(CampfirePotRecipeCategory.RECIPE_TYPE, cookingRecipes)
}
override fun registerRecipeCatalsysts(registration: IRecipeCatalystRegistration) {
CobblemonItems.campfire_pots.forEach {
registration.addRecipeCatalyst(it, CampfirePotRecipeCategory.RECIPE_TYPE)
}
}
}
@@ -1,122 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.jei.cooking
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.CRAFTING_GRID_WIDTH
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.SEASONING_SLOTS
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen.Companion.COOK_PROGRESS_HEIGHT
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen.Companion.COOK_PROGRESS_SPRITE
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen.Companion.COOK_PROGRESS_WIDTH
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import mezz.jei.api.constants.VanillaTypes
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder
import mezz.jei.api.gui.drawable.IDrawable
import mezz.jei.api.gui.drawable.IDrawableAnimated
import mezz.jei.api.gui.ingredient.IRecipeSlotsView
import mezz.jei.api.helpers.IGuiHelper
import mezz.jei.api.recipe.IFocusGroup
import mezz.jei.api.recipe.RecipeIngredientRole
import mezz.jei.api.recipe.RecipeType
import mezz.jei.api.recipe.category.IRecipeCategory
import mezz.jei.api.registration.IRecipeCategoryRegistration
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.crafting.Ingredient
class CampfirePotRecipeCategory(registration: IRecipeCategoryRegistration) : IRecipeCategory<CookingPotRecipeBase> {
companion object {
val RECIPE_TYPE = RecipeType.create("cobblemon", "campfire_pot_recipe", CookingPotRecipeBase::class.java)!!
val CAMPFIRE_POT_TEXTURE: ResourceLocation = cobblemonResource("textures/gui/jei/campfire_pot.png")
const val TEXTURE_WIDTH = 146
const val TEXTURE_HEIGHT = 59
const val WIDTH = 146
const val HEIGHT = 59
val EXAMPLE_SEASONINGS = BuiltInRegistries.ITEM.map { it.defaultInstance }.filter { Seasonings.isSeasoning(it) }
}
val guiHelper: IGuiHelper = registration.jeiHelpers.guiHelper
val campfirePotBackground: IDrawable = guiHelper.drawableBuilder(CAMPFIRE_POT_TEXTURE, 0, 0, WIDTH, HEIGHT)
.setTextureSize(TEXTURE_WIDTH, TEXTURE_HEIGHT)
.build()
val cookProgressSprite: IDrawableAnimated =
guiHelper.drawableBuilder(COOK_PROGRESS_SPRITE, 0, 0, COOK_PROGRESS_WIDTH, COOK_PROGRESS_HEIGHT)
.setTextureSize(22, COOK_PROGRESS_HEIGHT)
.buildAnimated(CampfireBlockEntity.COOKING_TOTAL_TIME, IDrawableAnimated.StartDirection.LEFT, false)
val campfirePotIcon: IDrawable = guiHelper.createDrawableItemStack(CobblemonItems.CAMPFIRE_POT_BLACK.defaultInstance)
override fun getRecipeType(): RecipeType<CookingPotRecipeBase?>? = RECIPE_TYPE
override fun getTitle(): Component? = lang("container.campfire_pot")
override fun getBackground(): IDrawable? = campfirePotBackground
override fun getIcon(): IDrawable? = campfirePotIcon
override fun setRecipe(
builder: IRecipeLayoutBuilder,
recipe: CookingPotRecipeBase,
focuses: IFocusGroup
) {
recipe.ingredients.forEachIndexed { index, ingredient ->
val column = index / CRAFTING_GRID_WIDTH
val row = index % CRAFTING_GRID_WIDTH
val x = 16 + row * 18
val y = 1 + column * 18
builder.addSlot(RecipeIngredientRole.INPUT, x, y).addIngredients(ingredient)
}
if (recipe.seasoningProcessors.isNotEmpty()) {
val processedSeasonings = EXAMPLE_SEASONINGS.filter { item ->
var valid = true
if (!item.`is`(recipe.seasoningTag)) return@filter false
recipe.seasoningProcessors.forEach {
if (!it.consumesItem(item)) {
valid = false
return@forEach
}
}
valid
}
for ((index, _) in SEASONING_SLOTS.withIndex()) {
val x = 93 + index * 18
val y = 1
builder.addSlot(RecipeIngredientRole.INPUT, x, y)
.addIngredients(VanillaTypes.ITEM_STACK, processedSeasonings.shuffled())
}
}
val registryAccess = Minecraft.getInstance().level?.registryAccess() ?: throw IllegalStateException("Registry access not found")
builder.addSlot(RecipeIngredientRole.OUTPUT, 111, 38).addIngredients(Ingredient.of(recipe.getResultItem(registryAccess)))
}
override fun draw(
recipe: CookingPotRecipeBase,
recipeSlotsView: IRecipeSlotsView,
guiGraphics: GuiGraphics,
mouseX: Double,
mouseY: Double
) {
super.draw(recipe, recipeSlotsView, guiGraphics, mouseX, mouseY)
cookProgressSprite.draw(guiGraphics, 79, 22)
}
}
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.inventory.AbstractContainerMenu
data class RecipeClickArea(
val containerScreen: Class<AbstractContainerScreen<AbstractContainerMenu>>,
val x: Int,
val y: Int,
val width: Int,
val height: Int
)
@@ -0,0 +1,17 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer
import net.minecraft.world.item.crafting.Ingredient
// Whole existence due to the fact we can have recipes with multiple count requirement
data class RecipeIngredient(
val ingredient: Ingredient,
val count: Int = 1
)
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer
data class RecipeSlot(
val x: Int,
val y: Int,
val type: SlotType,
val ingredient: RecipeIngredient
)
enum class SlotType {
INPUT,
OUTPUT,
CATALYST
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer
import com.cobblemon.mod.common.integration.recipeviewer.berry.BerryMutationProvider
import com.cobblemon.mod.common.integration.recipeviewer.cooking.CampfirePotViewerProvider
import com.cobblemon.mod.common.integration.recipeviewer.tm.TMViewerProvider
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
import org.joml.Vector2i
interface RecipeViewerCategoryProvider<T: RecipeViewerRecipe> {
companion object {
val categoriesProviders: Set<RecipeViewerCategoryProvider<*>> = setOf(
BerryMutationProvider(),
CampfirePotViewerProvider(),
TMViewerProvider()
)
}
val recipeClass: Class<T>
val id: ResourceLocation
fun getName(): Component = Component.translatable("${id.namespace}.recipeviewer.category.${id.path}")
fun getIconResource(): ResourceLocation
fun getIconDimensions(): Vector2i
fun getRecipes(): List<T>
fun getWorkstations(): List<ItemStack>
fun getHeight(): Int
fun getWidth(): Int
fun getClickArea(): RecipeClickArea? = null
fun recipeHandler(): List<RecipeViewerRecipeHandler<T, AbstractContainerMenu>> = listOf()
}
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import net.minecraft.core.component.DataComponentType
import net.minecraft.world.item.Item
object RecipeViewerComponentRegistry {
fun register(method: (item: Item, component: DataComponentType<*>) -> Unit) {
method(CobblemonItems.TECHNICAL_MACHINE, CobblemonItemComponents.TM_MOVE)
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
interface RecipeViewerRecipe {
fun getId(): ResourceLocation
fun getInputs(): List<RecipeIngredient>
fun getOutputs(): List<ItemStack>
fun getOptionalInputs(): List<RecipeIngredient> = emptyList()
fun supportsRecipeTree(): Boolean = true
fun renderRecipe(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {}
fun getSlots(): List<RecipeSlot>
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.inventory.Slot
interface RecipeViewerRecipeHandler<T: RecipeViewerRecipe, E: AbstractContainerMenu> {
fun getInputSlots(menu: E): List<Slot> //Returns crafting slots
fun getInventorySlots(menu: E): List<Slot>
fun getMenuClass(): Class<E>
fun getMenuType(): MenuType<E>
fun isApplicable(recipe: T): Boolean = true
fun additionalHandle(recipe: T, menu: E, screen: AbstractContainerScreen<E>?) {}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.berry
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import org.joml.Vector2i
class BerryMutationProvider: RecipeViewerCategoryProvider<BerryMutationRecipe> {
override val id = ID
override val recipeClass = BerryMutationRecipe::class.java
override fun getIconResource(): ResourceLocation = cobblemonResource("textures/item/mulches/surprise_mulch.png")
override fun getIconDimensions(): Vector2i = Vector2i(16, 16)
override fun getWidth(): Int = WIDTH
override fun getHeight(): Int = HEIGHT
override fun getRecipes(): List<BerryMutationRecipe> {
val berryList = CobblemonItems.berries().map { it.value }
val berryMutations = mutableSetOf<Triple<BerryItem, BerryItem, BerryItem>>()
berryList.forEach {berry ->
for (mut in berry.berry()?.mutations?.entries ?: emptySet()) {
val berryTwo = CobblemonItems.berries()[mut.key] ?: continue
val berryThree = CobblemonItems.berries()[mut.value] ?: continue
val mutation = Triple(berry, berryTwo, berryThree)
val altMutation = Triple(berryTwo, berry, berryThree)
if (!(berryMutations.contains(mutation) || berryMutations.contains(altMutation))) {
berryMutations.add(mutation)
}
}
}
return berryMutations.map { values ->
BerryMutationRecipe(values.first, values.second, values.third) }
}
override fun getWorkstations(): List<ItemStack> {
return emptyList()
}
companion object {
private const val WIDTH = 125
private const val HEIGHT = 18
val ID = cobblemonResource("berry_recipe")
}
}
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.berry
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.integration.recipeviewer.RecipeIngredient
import com.cobblemon.mod.common.integration.recipeviewer.RecipeSlot
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.SlotType
import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
//Dont make these ItemStacks, they do not have consistent hash codes, breaks stuff
data class BerryMutationRecipe(
val berryOne: BerryItem,
val berryTwo: BerryItem,
val berryResult: BerryItem
): RecipeViewerRecipe {
companion object {
val BACKGROUND = cobblemonResource("textures/gui/recipeviewer/berry_mutation.png")
}
override fun getId() = cobblemonResource("/berry_mutation_" +
"${berryIdentifier(berryResult)}_${berryIdentifier(berryOne)}_${berryIdentifier(berryTwo)}")
override fun getInputs(): List<RecipeIngredient> {
return listOf(RecipeIngredient(Ingredient.of(berryOne)), RecipeIngredient(Ingredient.of(berryTwo)))
}
override fun getOutputs(): List<ItemStack> {
return listOf(berryResult.defaultInstance)
}
override fun supportsRecipeTree(): Boolean = false
override fun renderRecipe(
context: GuiGraphics,
mouseX: Int,
mouseY: Int,
delta: Float
) {
blitk(
matrixStack = context.pose(),
texture = BACKGROUND,
x = 0,
y = 0,
width = 125,
height = 18
)
}
override fun getSlots(): List<RecipeSlot> {
val list = mutableListOf<RecipeSlot>()
list.add(RecipeSlot(1, 1, SlotType.INPUT, RecipeIngredient(Ingredient.of(berryOne))))
list.add(RecipeSlot(50, 1, SlotType.INPUT, RecipeIngredient(Ingredient.of(berryTwo))))
list.add(RecipeSlot(108, 1, SlotType.OUTPUT, RecipeIngredient(Ingredient.of(berryResult))))
return list
}
private fun berryIdentifier(berry: BerryItem): String {
return berry.berry()?.identifier?.path ?: ""
}
}
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.brewing
import com.cobblemon.mod.common.CobblemonRecipeTypes
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe
import net.minecraft.client.Minecraft
import net.minecraft.world.item.crafting.RecipeHolder
object CobblemonBrewingRecipeProvider { // This has custom implementation
fun getRecipes(): List<RecipeHolder<BrewingStandRecipe>> {
val recipeManger =
Minecraft.getInstance().level?.recipeManager ?: throw IllegalStateException("Recipe manager not found")
return recipeManger.getAllRecipesFor(CobblemonRecipeTypes.BREWING_STAND)
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.cooking
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonRecipeTypes
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
import com.cobblemon.mod.common.integration.recipeviewer.RecipeClickArea
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import org.joml.Vector2i
class CampfirePotViewerProvider: RecipeViewerCategoryProvider<CampfirePotViewerRecipe> {
override val id = ID
override val recipeClass = CampfirePotViewerRecipe::class.java
override fun getIconResource(): ResourceLocation = cobblemonResource("textures/item/campfire_pots/campfire_pot_red.png")
override fun getIconDimensions(): Vector2i = Vector2i(16, 16)
override fun getWidth(): Int = WIDTH
override fun getHeight(): Int = HEIGHT
override fun getRecipes(): List<CampfirePotViewerRecipe> {
val recipeManger = Minecraft.getInstance().level?.recipeManager ?: throw IllegalStateException("Recipe manager not found")
val recipeList = mutableListOf<CampfirePotViewerRecipe>()
recipeManger.getAllRecipesFor(CobblemonRecipeTypes.COOKING_POT_SHAPELESS).forEach {
recipeList.add(CampfirePotViewerRecipe(it.id, it.value))
}
recipeManger.getAllRecipesFor(CobblemonRecipeTypes.COOKING_POT_COOKING).forEach {
recipeList.add(CampfirePotViewerRecipe(it.id, it.value))
}
return recipeList
}
override fun getWorkstations(): List<ItemStack> {
return CobblemonItems.campfire_pots.map { it.defaultInstance }
}
override fun getClickArea(): RecipeClickArea = RecipeClickArea(CookingPotScreen::class.java as Class<AbstractContainerScreen<AbstractContainerMenu>>, 96, 39 ,
CookingPotScreen.COOK_PROGRESS_WIDTH, CookingPotScreen.COOK_PROGRESS_HEIGHT)
override fun recipeHandler(): List<RecipeViewerRecipeHandler<CampfirePotViewerRecipe, AbstractContainerMenu>> = listOf(CampfirePotViewerRecipeHandler() as RecipeViewerRecipeHandler<CampfirePotViewerRecipe, AbstractContainerMenu>)
companion object {
private const val WIDTH = 146
private const val HEIGHT = 59
val ID = cobblemonResource("cooking_pot_recipe")
}
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.cooking
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase
import net.minecraft.client.Minecraft
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.CRAFTING_GRID_WIDTH
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.SEASONING_SLOTS
import com.cobblemon.mod.common.integration.recipeviewer.RecipeIngredient
import com.cobblemon.mod.common.integration.recipeviewer.RecipeSlot
import com.cobblemon.mod.common.integration.recipeviewer.SlotType
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
class CampfirePotViewerRecipe(val theId: ResourceLocation, val originalRecipe: CookingPotRecipeBase): RecipeViewerRecipe {
companion object {
val EXAMPLE_SEASONINGS = BuiltInRegistries.ITEM.map { it.defaultInstance }.filter { Seasonings.isSeasoning(it) }
val BACKGROUND = cobblemonResource("textures/gui/recipeviewer/campfire_pot.png")
}
override fun getId(): ResourceLocation = theId
override fun getInputs(): List<RecipeIngredient> {
return originalRecipe.ingredients.map { RecipeIngredient(it) }
}
override fun getOutputs(): List<ItemStack> {
val registryAccess = Minecraft.getInstance().level?.registryAccess() ?: throw IllegalStateException("Registry access not found")
return listOf(originalRecipe.getResultItem(registryAccess))
}
override fun getOptionalInputs(): List<RecipeIngredient> {
return listOf(RecipeIngredient(Ingredient.of(*generateProperSeasoningList().toTypedArray())))
}
override fun getSlots(): List<RecipeSlot> {
val registryAccess = Minecraft.getInstance().level?.registryAccess() ?: throw IllegalStateException("Registry access not found")
val slots = mutableListOf<RecipeSlot>()
originalRecipe.ingredients.forEachIndexed { index, ingredient ->
val row = index / CRAFTING_GRID_WIDTH
val column = index % CRAFTING_GRID_WIDTH
slots.add(RecipeSlot(16 + column * 18, 1 + row * 18,
SlotType.INPUT, RecipeIngredient(ingredient)))
}
if (originalRecipe.seasoningProcessors.isNotEmpty()) {
val processedSeasonings = generateProperSeasoningList()
for ((index, _) in SEASONING_SLOTS.withIndex()) {
val x = 93 + index * 18
val y = 1
slots.add(RecipeSlot(x, y,
SlotType.CATALYST, RecipeIngredient(Ingredient.of(*processedSeasonings.shuffled().toTypedArray()))))
}
}
slots.add(RecipeSlot(111, 38,
SlotType.OUTPUT, RecipeIngredient(Ingredient.of(originalRecipe.getResultItem(registryAccess)))))
return slots
}
override fun renderRecipe(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
blitk(
matrixStack = context.pose(),
texture = BACKGROUND,
x = 0,
y = 0,
width = 146,
height = 59
)
}
private fun generateProperSeasoningList(): List<ItemStack> {
if (originalRecipe.seasoningProcessors.isEmpty()) return emptyList()
val processedSeasonings = EXAMPLE_SEASONINGS.filter { item ->
var valid = true
if (!item.`is`(originalRecipe.seasoningTag)) return@filter false
originalRecipe.seasoningProcessors.forEach {
if (!it.consumesItem(item)) {
valid = false
return@forEach
}
}
valid
}
return processedSeasonings
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.cooking
import com.cobblemon.mod.common.CobblemonMenuType
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.inventory.Slot
class CampfirePotViewerRecipeHandler: RecipeViewerRecipeHandler<CampfirePotViewerRecipe, CookingPotMenu> {
override fun getInputSlots(menu: CookingPotMenu): List<Slot> {
return menu.slots.filter { it.index in CampfireBlockEntity.CRAFTING_GRID_SLOTS }
}
override fun getInventorySlots(menu: CookingPotMenu): List<Slot> {
return menu.slots.filter { it.index in CampfireBlockEntity.PLAYER_INVENTORY_SLOTS || it.index in CampfireBlockEntity.PLAYER_HOTBAR_SLOTS }
}
override fun getMenuClass(): Class<CookingPotMenu> = CookingPotMenu::class.java
override fun getMenuType(): MenuType<CookingPotMenu> = CobblemonMenuType.COOKING_POT
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.tm
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import org.joml.Vector2i
class TMViewerProvider: RecipeViewerCategoryProvider<TMViewerRecipe> {
override val id = ID
override val recipeClass = TMViewerRecipe::class.java
override fun getIconResource(): ResourceLocation = cobblemonResource("textures/item/tms/blank_disc.png")
override fun getIconDimensions(): Vector2i = Vector2i(16, 16)
override fun getWidth(): Int = WIDTH
override fun getHeight(): Int = HEIGHT
override fun getRecipes(): List<TMViewerRecipe> {
return TechnicalMachines.tmMap.values.map { TMViewerRecipe(it) }.sortedBy { it.originalTM.type }
}
override fun getWorkstations(): List<ItemStack> {
return listOf(CobblemonItems.TM_MACHINE.defaultInstance)
}
override fun recipeHandler(): List<RecipeViewerRecipeHandler<TMViewerRecipe, AbstractContainerMenu>> = listOf(TMViewerRecipeHandler() as RecipeViewerRecipeHandler<TMViewerRecipe, AbstractContainerMenu>)
companion object {
private const val WIDTH = 125
private const val HEIGHT = 30
val ID = cobblemonResource("tm_recipe")
}
}
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.tm
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.tms.TechnicalMachine
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.integration.recipeviewer.RecipeIngredient
import com.cobblemon.mod.common.integration.recipeviewer.RecipeSlot
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.SlotType
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
class TMViewerRecipe(val originalTM: TechnicalMachine): RecipeViewerRecipe {
companion object {
val BACKGROUND = cobblemonResource("textures/gui/recipeviewer/tm_recipe.png")
}
override fun getId(): ResourceLocation = cobblemonResource("/tm_recipe_" + originalTM.id.path)
override fun getInputs(): List<RecipeIngredient> {
val items = mutableListOf(RecipeIngredient(Ingredient.of(CobblemonItems.BLANK_TM)))
items.addAll(originalTM.recipe?.map { RecipeIngredient(it.ingredient, it.count) } ?: listOf())
return items
}
override fun getOutputs(): List<ItemStack> {
return listOf(originalTM.createItemStack())
}
override fun getSlots(): List<RecipeSlot> {
val slots = mutableListOf<RecipeSlot>()
val recipe = originalTM.recipe ?: listOf()
slots.add(RecipeSlot(1, 1, SlotType.INPUT, RecipeIngredient(Ingredient.of(CobblemonItems.BLANK_TM))))
for (i in 0..2) {
val ingredient = recipe.getOrNull(i)?.let { RecipeIngredient(it.ingredient, it.count) } ?: RecipeIngredient(Ingredient.of())
slots.add(RecipeSlot(24 + i * 18, 1, SlotType.INPUT, ingredient))
}
slots.add(RecipeSlot(108, 1, SlotType.OUTPUT, RecipeIngredient(Ingredient.of(originalTM.createItemStack()))))
return slots
}
override fun renderRecipe(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
blitk(
matrixStack = context.pose(),
texture = BACKGROUND,
x = 0,
y = 0,
width = 125,
height = 30
)
drawScaledText(
context = context,
text = if (recipeKnown()) lang("recipeviewer.tm_learned") else lang("recipeviewer.tm_not_learned").red(),
x = 0,
y = 21,
shadow = true
)
}
fun recipeKnown(): Boolean {
val learnedTMs = CobblemonClient.clientTMMoveData.learnedTMs
return originalTM.isPassivelyObtained() || originalTM.id in learnedTMs
}
}
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.recipeviewer.tm
import com.cobblemon.mod.common.CobblemonMenuType
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.block.entity.TMMachineBlockEntity
import com.cobblemon.mod.common.block.tmmachine.TMMachineMenu
import com.cobblemon.mod.common.client.gui.tmmachine.TMMachineScreen
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import com.cobblemon.mod.common.net.messages.client.ui.SetActiveTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.SetTMMachineContainerDataPacket
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.inventory.Slot
class TMViewerRecipeHandler: RecipeViewerRecipeHandler<TMViewerRecipe, TMMachineMenu> {
override fun getInputSlots(menu: TMMachineMenu): List<Slot> {
return menu.slots.filter { it.index in 37..40 }
}
override fun getInventorySlots(menu: TMMachineMenu): List<Slot> {
return menu.slots.filter { it.index in 0..35}
}
override fun getMenuClass(): Class<TMMachineMenu> = TMMachineMenu::class.java
override fun getMenuType(): MenuType<TMMachineMenu> = CobblemonMenuType.TM_MACHINE
override fun isApplicable(recipe: TMViewerRecipe): Boolean {
return recipe.recipeKnown()
}
override fun additionalHandle(recipe: TMViewerRecipe, menu: TMMachineMenu, screen: AbstractContainerScreen<TMMachineMenu>?) {
(screen as? TMMachineScreen)?.let {
it.setScreenFromMode(TMMachineScreen.TM_BURN_MODE)
it.sortType = ElementalTypes.get(recipe.originalTM.type)
it.setMoveList()
}
if (menu.currentlySelectedTM != recipe.originalTM) {
CobblemonNetwork.sendToServer(SetActiveTMPacket(recipe.originalTM))
}
}
}
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.SlotType
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.util.EntryIngredients
import net.minecraft.network.chat.Component
class CobblemonReiCategory<T: RecipeViewerRecipe>(val provider: CobblemonReiProvider<T>): DisplayCategory<CobblemonReiDisplay<T>> {
companion object {
private const val PADDING = 4
}
val theIcon = CobblemonReiIcon(provider.originalProvider.getIconResource(), provider.originalProvider.getIconDimensions().x, provider.originalProvider.getIconDimensions().y)
override fun getCategoryIdentifier(): CategoryIdentifier<CobblemonReiDisplay<T>> = provider.categoryIdentifier
override fun getIcon(): Renderer = theIcon
override fun getTitle(): Component = provider.originalProvider.getName()
// Add Padding so insides fit perfectly
override fun getDisplayWidth(display: CobblemonReiDisplay<T>): Int = provider.originalProvider.getWidth() + PADDING * 2
override fun getDisplayHeight(): Int = provider.originalProvider.getHeight() + PADDING * 2
override fun setupDisplay(display: CobblemonReiDisplay<T>, bounds: Rectangle): List<Widget> {
val widgets = mutableListOf<Widget>()
val startX = bounds.minX + PADDING
val startY = bounds.minY + PADDING
widgets.add(Widgets.createCategoryBase(bounds))
widgets.add(CobblemonReiSimpleWidget(startX, startY, display.recipe))
display.recipe.getSlots().forEach { slot ->
val reiSlot = Widgets.createSlot(Point(startX + slot.x, startY + slot.y))
reiSlot.entries(EntryIngredients.ofItemStacks(slot.ingredient.ingredient.items.map { it.copyWithCount(slot.ingredient.count) }))
reiSlot.disableBackground()
when (slot.type) {
SlotType.INPUT -> reiSlot.markInput()
SlotType.CATALYST -> reiSlot.markInput()
SlotType.OUTPUT -> reiSlot.markOutput()
}
widgets.add(reiSlot)
}
return widgets
}
}
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerComponentRegistry
import com.cobblemon.mod.common.integration.recipeviewer.brewing.CobblemonBrewingRecipeProvider
import com.cobblemon.mod.common.integration.rei.brewing.ReiCobblemonBrewingDisplay
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
import me.shedaniel.rei.api.client.registry.entry.EntryRegistry
import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry
import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry
import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry
import me.shedaniel.rei.api.common.util.EntryStacks
open class CobblemonReiClientPlugin: REIClientPlugin {
companion object {
private val reiProviders = RecipeViewerCategoryProvider.categoriesProviders.map {
CobblemonReiProvider(it)
}
}
override fun registerDisplays(registry: DisplayRegistry) {
reiProviders.forEach {
it.registerDisplay(registry)
}
// Cobblemon Brewing Recipes
CobblemonBrewingRecipeProvider.getRecipes().forEach {
registry.add(ReiCobblemonBrewingDisplay(it.value, it.id))
}
}
override fun registerCategories(registry: CategoryRegistry) {
reiProviders.forEach {
it.registerCategory(registry)
}
}
override fun registerScreens(registry: ScreenRegistry) {
reiProviders.forEach {
it.registerScreens(registry)
}
}
override fun registerTransferHandlers(registry: TransferHandlerRegistry) {
reiProviders.forEach {
it.registerTransferHandlers(registry)
}
}
override fun registerItemComparators(registry: ItemComparatorRegistry) {
RecipeViewerComponentRegistry.register { item, component ->
registry.register(CobblemonReiComponentComparator(component), item)
}
}
}
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext
import me.shedaniel.rei.api.common.entry.comparison.EntryComparator
import net.minecraft.core.component.DataComponentType
import net.minecraft.world.item.ItemStack
class CobblemonReiComponentComparator(val component: DataComponentType<*>): EntryComparator<ItemStack> {
override fun hash(context: ComparisonContext, stack: ItemStack): Long {
return stack.get(component).hashCode().toLong()
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import me.shedaniel.rei.api.common.category.CategoryIdentifier
import me.shedaniel.rei.api.common.display.Display
import me.shedaniel.rei.api.common.entry.EntryIngredient
import me.shedaniel.rei.api.common.entry.EntryStack
import me.shedaniel.rei.api.common.entry.InputIngredient
import me.shedaniel.rei.api.common.util.EntryIngredients
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import java.util.Optional
class CobblemonReiDisplay<T: RecipeViewerRecipe>(val recipe: T, val categoryId: CategoryIdentifier<*>): Display {
override fun getCategoryIdentifier(): CategoryIdentifier<*> = categoryId
override fun getInputEntries(): List<EntryIngredient> {
val entries = recipe.getInputs().map { EntryIngredients.ofItems(it.ingredient.items.map { it.item }, it.count) }.toMutableList()
entries.addAll(recipe.getOptionalInputs().map { EntryIngredients.ofItemStacks(it.ingredient.items.map { it.copyWithCount(it.count) }) })
return entries
}
override fun getOutputEntries(): List<EntryIngredient> {
return recipe.getOutputs().map { EntryIngredients.of(it) }
}
override fun getRequiredEntries(): List<EntryIngredient> {
return recipe.getInputs().map { EntryIngredients.ofItemStacks(it.ingredient.items.map { it.copyWithCount(it.count) }) }
}
override fun getDisplayLocation(): Optional<ResourceLocation> = Optional.of(recipe.getId())
override fun getInputIngredients(
menu: AbstractContainerMenu?,
player: Player?
): List<InputIngredient<EntryStack<*>>> {
return recipe.getInputs().mapIndexed { index, ingredient -> InputIngredient.of(index, EntryIngredients.ofIngredient(ingredient.ingredient)) }
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import com.cobblemon.mod.common.api.gui.blitk
import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.client.gui.Renderer
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.resources.ResourceLocation
class CobblemonReiIcon(val iconResource: ResourceLocation, val width: Int, val height: Int): Renderer {
override fun render(graphics: GuiGraphics, bounds: Rectangle, mouseX: Int, mouseY: Int, delta: Float) {
blitk(
matrixStack = graphics.pose(),
texture = iconResource,
x = bounds.minX,
y = bounds.minY,
width = width,
height = height
)
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerCategoryProvider
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.client.registry.category.CategoryRegistry
import me.shedaniel.rei.api.client.registry.display.DisplayRegistry
import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry
import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry
import me.shedaniel.rei.api.common.category.CategoryIdentifier
import me.shedaniel.rei.api.common.util.EntryStacks
import net.minecraft.world.inventory.AbstractContainerMenu
class CobblemonReiProvider<T: RecipeViewerRecipe>(val originalProvider: RecipeViewerCategoryProvider<T>) {
val categoryIdentifier: CategoryIdentifier<CobblemonReiDisplay<T>> = CategoryIdentifier.of<CobblemonReiDisplay<T>>(originalProvider.id)
fun registerDisplay(registry: DisplayRegistry) {
originalProvider.getRecipes().forEach {
registry.add(CobblemonReiDisplay(it, categoryIdentifier))
}
}
fun registerCategory(registry: CategoryRegistry) {
registry.add(CobblemonReiCategory(this))
registry.addWorkstations(categoryIdentifier, *originalProvider.getWorkstations().map { EntryStacks.of(it) }.toTypedArray())
}
fun registerScreens(registry: ScreenRegistry) {
originalProvider.getClickArea()?.let { registry.registerContainerClickArea(Rectangle(it.x, it.y, it.width, it.height), it.containerScreen, categoryIdentifier) }
}
fun registerTransferHandlers(registry: TransferHandlerRegistry) {
originalProvider.recipeHandler().forEach { registry.register(CobblemonReiRecipeHandler(this,it)) }
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipeHandler
import me.shedaniel.rei.api.client.registry.transfer.TransferHandler
import me.shedaniel.rei.api.client.registry.transfer.simple.SimpleTransferHandler
import me.shedaniel.rei.api.common.entry.InputIngredient
import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessor
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
class CobblemonReiRecipeHandler<E: AbstractContainerMenu, R: RecipeViewerRecipe>(val provider: CobblemonReiProvider<*>, val originalHandler: RecipeViewerRecipeHandler<R, E>): SimpleTransferHandler {
override fun checkApplicable(context: TransferHandler.Context): TransferHandler.ApplicabilityResult {
val display = context.display as? CobblemonReiDisplay<R>
if (display == null || display.categoryId != provider.categoryIdentifier || context.menu == null
|| !originalHandler.getMenuClass().isInstance(context.menu) || !originalHandler.isApplicable(display.recipe))
return TransferHandler.ApplicabilityResult.createNotApplicable()
return TransferHandler.ApplicabilityResult.createApplicable()
}
override fun getInputSlots(context: TransferHandler.Context): Iterable<SlotAccessor> {
return originalHandler.getInputSlots(context.menu!! as E).map { SlotAccessor.fromSlot(it) }
}
override fun getInventorySlots(context: TransferHandler.Context): Iterable<SlotAccessor> {
return originalHandler.getInventorySlots(context.menu!! as E).map { SlotAccessor.fromSlot(it) }
}
override fun handle(context: TransferHandler.Context): TransferHandler.Result {
if (context.isActuallyCrafting) {
val display = context.display as? CobblemonReiDisplay<R>
display?.let {
originalHandler.additionalHandle(display.recipe, context.menu as E, context.containerScreen as AbstractContainerScreen<E>)
}
}
return super.handle(context)
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei
import com.cobblemon.mod.common.integration.recipeviewer.RecipeViewerRecipe
import me.shedaniel.rei.api.client.gui.widgets.Widget
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.events.GuiEventListener
class CobblemonReiSimpleWidget<T: RecipeViewerRecipe>(val x: Int, val y: Int, val recipe: T): Widget() {
override fun children(): List<GuiEventListener> {
return emptyList()
}
override fun render(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
val realDelta = Minecraft.getInstance().timer.realtimeDeltaTicks
val matrices = guiGraphics.pose()
matrices.pushPose()
matrices.translate(x.toDouble(), y.toDouble(), 0.0)
recipe.renderRecipe(guiGraphics, mouseX, mouseY, realDelta)
matrices.popPose()
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.integration.rei.brewing
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe
import me.shedaniel.rei.plugin.common.displays.brewing.DefaultBrewingDisplay
import net.minecraft.resources.ResourceLocation
import java.util.Optional
class ReiCobblemonBrewingDisplay(
val recipe: BrewingStandRecipe,
val id: ResourceLocation
): DefaultBrewingDisplay(
recipe.bottle,
recipe.input,
recipe.result
) {
override fun getDisplayLocation(): Optional<ResourceLocation> = Optional.of(id)
}
@@ -38,7 +38,7 @@ abstract class PlatformRegistry<R : Registry<T>, K : ResourceKey<R>, T> {
*/
abstract val resourceKey: K
protected val queue = hashMapOf<ResourceLocation, T>()
protected val queue = mutableMapOf<ResourceLocation, T>()
/**
* Creates a new entry in this registry.
@@ -9472,5 +9472,11 @@
"stat.cobblemon.reel_ins": "PokéRod Catches",
"stat.cobblemon.riding_land": "Distance by Pokémon on Land",
"stat.cobblemon.riding_air": "Distance by Pokémon in Air",
"stat.cobblemon.riding_liquid": "Distance by Pokémon in Liquid"
}
"stat.cobblemon.riding_liquid": "Distance by Pokémon in Liquid",
"cobblemon.recipeviewer.category.berry_recipe": "Berry Mutations",
"cobblemon.recipeviewer.category.cooking_pot_recipe": "Pot Cooking",
"cobblemon.recipeviewer.category.tm_recipe": "TM Burning",
"cobblemon.recipeviewer.tm_learned": "TM Discovered",
"cobblemon.recipeviewer.tm_not_learned": "TM Undiscovered"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

-1
View File
@@ -84,7 +84,6 @@ dependencies {
}
minecraftServerLibraries(libs.icu4j)
}
publishing {
@@ -33,6 +33,12 @@
],
"modmenu": [
"com.cobblemon.mod.fabric.client.integration.modmenu.CobblemonModMenu"
],
"emi": [
"com.cobblemon.mod.common.integration.emi.CobblemonEmiPlugin"
],
"rei_client": [
"com.cobblemon.mod.common.integration.rei.CobblemonReiClientPlugin"
]
},
"mixins": [
+6
View File
@@ -17,6 +17,8 @@ moddev = "1.0.11"
# Common
molang = "1.1.20"
jei-api = "19.22.1.316"
emi-api = "1.1.22+1.21.1"
rei-api = "16.0.799"
# Graal
graal = "22.3.0"
@@ -68,6 +70,9 @@ kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", vers
# Common
jei-api = { group = "mezz.jei", name = "jei-1.21.1-common-api", version.ref = "jei-api"}
molang = { group = "local.com.bedrockk", name = "molang", version.ref = "molang" }
emi = { group = "dev.emi", name = "emi-xplat-intermediary", version.ref = "emi-api"}
rei-api = { group = "me.shedaniel", name = "RoughlyEnoughItems-api", version.ref = "rei-api"}
rei-defaultplugin = { group = "me.shedaniel", name = "RoughlyEnoughItems-default-plugin", version.ref = "rei-api"}
# Graal
graal-core = { group = "org.graalvm.js", name = "js", version.ref = "graal" }
@@ -93,6 +98,7 @@ neoforge-api = { group = "net.neoforged", name = "neoforge", version.ref = "neof
neo-kotlin-forge = { group = "thedarkcolour", name = "kotlinforforge-neoforge", version.ref = "neo-kotlin-for-forge" }
neoforge-debugutils = { group = "maven.modrinth", name = "debugutils", version.ref = "debugutils-forge"}
jei-neoforge = { group = "mezz.jei", name = "jei-1.21.1-neoforge", version.ref = "jei-api"}
rei-neoforge-api = { group = "me.shedaniel", name = "RoughlyEnoughItems-api-neoforge", version.ref = "rei-api"}
c2me-neoforge = { group = "maven.modrinth", name = "c2me-neoforge", version.ref = "c2me-neoforge" }
# Data Storage
+3
View File
@@ -29,6 +29,8 @@ repositories {
maven(url = "https://thedarkcolour.github.io/KotlinForForge/")
maven(url = "https://api.modrinth.com/maven")
maven(url = "https://maven.neoforged.net/releases")
maven(url = "https://maven.terraformersmc.com/")
maven(url = "https://maven.shedaniel.me")
mavenLocal()
}
@@ -68,6 +70,7 @@ dependencies {
bundle(it)
}
modCompileOnlyApi(libs.rei.neoforge.api)
}
tasks {
@@ -0,0 +1,15 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.neoforge.integration.rei
import com.cobblemon.mod.common.integration.rei.CobblemonReiClientPlugin
import me.shedaniel.rei.forge.REIPluginClient
@REIPluginClient
class CobblemonReiPluginNeoforge: CobblemonReiClientPlugin()