From e16c60169bf192b79991176b5f9cee66b5b16e7d Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Tue, 24 Dec 2024 03:58:43 +0100 Subject: WIP: Reforge recipes --- .../nea/firmament/compat/rei/FirmamentReiPlugin.kt | 6 + .../compat/rei/recipes/SBReforgeRecipe.kt | 147 +++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt (limited to 'src/compat/rei/java/moe') diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt index f576eda..92f2cfc 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt @@ -24,6 +24,7 @@ import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe import moe.nea.firmament.compat.rei.recipes.SBKatRecipe import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe +import moe.nea.firmament.compat.rei.recipes.SBReforgeRecipe import moe.nea.firmament.events.HandledScreenPushREIEvent import moe.nea.firmament.features.inventory.CraftingOverlay import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen @@ -78,6 +79,7 @@ class FirmamentReiPlugin : REIClientPlugin { registry.add(SBForgeRecipe.Category) registry.add(SBMobDropRecipe.Category) registry.add(SBKatRecipe.Category) + registry.add(SBReforgeRecipe.Category) registry.add(SBEssenceUpgradeRecipe.Category) } @@ -90,6 +92,10 @@ class FirmamentReiPlugin : REIClientPlugin { registry.registerDisplayGenerator( SBCraftingRecipe.Category.catIdentifier, SkyblockCraftingRecipeDynamicGenerator) + registry.registerDisplayGenerator( + SBReforgeRecipe.catIdentifier, + SBReforgeRecipe.DynamicGenerator + ) registry.registerDisplayGenerator( SBForgeRecipe.Category.categoryIdentifier, SkyblockForgeRecipeDynamicGenerator) diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt new file mode 100644 index 0000000..2805132 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt @@ -0,0 +1,147 @@ +package moe.nea.firmament.compat.rei.recipes + +import java.util.Optional +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.client.registry.display.DynamicDisplayGenerator +import me.shedaniel.rei.api.client.view.ViewSearchBuilder +import me.shedaniel.rei.api.common.category.CategoryIdentifier +import me.shedaniel.rei.api.common.display.Display +import me.shedaniel.rei.api.common.display.DisplaySerializer +import me.shedaniel.rei.api.common.entry.EntryIngredient +import me.shedaniel.rei.api.common.entry.EntryStack +import net.minecraft.text.Text +import net.minecraft.util.Identifier +import moe.nea.firmament.Firmament +import moe.nea.firmament.compat.rei.SBItemEntryDefinition +import moe.nea.firmament.repo.Reforge +import moe.nea.firmament.repo.ReforgeStore +import moe.nea.firmament.repo.RepoItemTypeCache +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.repo.SBItemStack +import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.skyblock.ItemType +import moe.nea.firmament.util.skyblockId +import moe.nea.firmament.util.tr + +class SBReforgeRecipe( + val reforge: Reforge, + val limitToItem: SkyblockId?, +) : Display { + companion object { + val catIdentifier = CategoryIdentifier.of(Firmament.MOD_ID, "reforge_recipe") + } + + object Category : DisplayCategory { + override fun getCategoryIdentifier(): CategoryIdentifier { + return catIdentifier + } + + override fun getTitle(): Text { + return tr("firmament.recipecategory.reforge", "Reforge") + } + + override fun getIcon(): Renderer { + return SBItemEntryDefinition.getEntry(SkyblockId("REFORGE_ANVIL")) + } + + override fun setupDisplay(display: SBReforgeRecipe, bounds: Rectangle): MutableList { + val list = mutableListOf() + list.add(Widgets.createRecipeBase(bounds)) + // TODO: actual layout after christmas, probably + list.add(Widgets.createSlot(Point(bounds.minX + 10, bounds.centerY)) + .markInput().entries(display.inputItems)) + val stoneSlot = Widgets.createSlot(Point(bounds.minX + 38, bounds.centerY)) + .markInput() + if (display.reforgeStone != null) + stoneSlot.entry(display.reforgeStone) + list.add(stoneSlot) + list.add(Widgets.createSlot(Point(bounds.minX + 38 + 18, bounds.centerY)) + .markInput().entries(display.outputItems)) + return list + } + } + + object DynamicGenerator : DynamicDisplayGenerator { + fun getRecipesForSBItemStack(item: SBItemStack): Optional> { + val reforgeRecipes = mutableListOf() + for (reforge in ReforgeStore.findEligibleForInternalName(item.skyblockId)) { + reforgeRecipes.add(SBReforgeRecipe(reforge, item.skyblockId)) + } + for (reforge in ReforgeStore.findEligibleForItem(item.itemType ?: ItemType.NIL)) { + reforgeRecipes.add(SBReforgeRecipe(reforge, item.skyblockId)) + } + if (reforgeRecipes.isEmpty()) return Optional.empty() + return Optional.of(reforgeRecipes) + } + + override fun getRecipeFor(entry: EntryStack<*>): Optional> { + if (entry.type != SBItemEntryDefinition.type) return Optional.empty() + val item = entry.castValue() + return getRecipesForSBItemStack(item) + } + + override fun getUsageFor(entry: EntryStack<*>): Optional> { + if (entry.type != SBItemEntryDefinition.type) return Optional.empty() + val item = entry.castValue() + ReforgeStore.byReforgeStone[item.skyblockId]?.let { stoneReforge -> + return Optional.of(listOf(SBReforgeRecipe(stoneReforge, null))) + } + return getRecipesForSBItemStack(item) + } + + override fun generate(builder: ViewSearchBuilder): Optional> { + // TODO: check builder.recipesFor and such and optionally return all reforge recipes + return Optional.empty() + } + } + + private val eligibleItems = + if (limitToItem != null) listOfNotNull(RepoManager.getNEUItem(limitToItem)) + else reforge.eligibleItems.flatMap { + when (it) { + is Reforge.ReforgeEligibilityFilter.AllowsInternalName -> + listOfNotNull(RepoManager.getNEUItem(it.internalName)) + is Reforge.ReforgeEligibilityFilter.AllowsItemType -> + ReforgeStore.resolveItemType(it.itemType) + .flatMap { + RepoItemTypeCache.byItemType[it] ?: listOf() + } + + is Reforge.ReforgeEligibilityFilter.AllowsVanillaItemType -> { + listOf() // TODO: add filter support for this and potentially rework this to search for the declared item type in repo, instead of remapped item type + } + } + } + private val inputItems = eligibleItems.map { SBItemEntryDefinition.getEntry(it.skyblockId) } + private val outputItems = + inputItems.map { SBItemEntryDefinition.getEntry(it.value.copy(reforge = reforge.reforgeId)) } + private val reforgeStone = reforge.reforgeStone?.let(SBItemEntryDefinition::getEntry) + private val inputEntries = + listOf(EntryIngredient.of(inputItems)) + listOfNotNull(reforgeStone?.let(EntryIngredient::of)) + private val outputEntries = listOf(EntryIngredient.of(outputItems)) + + override fun getInputEntries(): List { + return inputEntries + } + + override fun getOutputEntries(): List { + return outputEntries + } + + override fun getCategoryIdentifier(): CategoryIdentifier<*> { + return catIdentifier + } + + override fun getDisplayLocation(): Optional { + return Optional.empty() + } + + override fun getSerializer(): DisplaySerializer? { + return null + } +} -- cgit From ddebaf47900dfab41590c97c202984142ae5b9f6 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Wed, 25 Dec 2024 16:15:20 +0100 Subject: WIP: Reforge Recipes --- .../moe/nea/firmament/compat/rei/EntityWidget.kt | 34 +++++++++++--- .../compat/rei/recipes/SBReforgeRecipe.kt | 52 ++++++++++++++++++---- 2 files changed, 71 insertions(+), 15 deletions(-) (limited to 'src/compat/rei/java/moe') diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt index d8238be..2b9e4bf 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt @@ -1,19 +1,22 @@ package moe.nea.firmament.compat.rei import me.shedaniel.math.Dimension +import me.shedaniel.math.FloatingDimension import me.shedaniel.math.Point import me.shedaniel.math.Rectangle import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.Drawable import net.minecraft.client.gui.Element -import net.minecraft.client.gui.ParentElement import net.minecraft.entity.LivingEntity import moe.nea.firmament.gui.entity.EntityRenderer import moe.nea.firmament.util.ErrorUtil -class EntityWidget(val entity: LivingEntity?, val point: Point) : WidgetWithBounds() { +class EntityWidget( + val entity: LivingEntity?, + val point: Point, + val size: FloatingDimension = FloatingDimension(defaultSize) +) : WidgetWithBounds() { override fun children(): List { return emptyList() } @@ -22,18 +25,35 @@ class EntityWidget(val entity: LivingEntity?, val point: Point) : WidgetWithBoun override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { try { - if (!hasErrored) - EntityRenderer.renderEntity(entity!!, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat()) + context.matrices.push() + if (!hasErrored) { + context.matrices.translate(point.x.toDouble(), point.y.toDouble(), 0.0) + val xScale = size.width / defaultSize.width.toDouble() + val yScale = size.height / defaultSize.height.toDouble() + context.matrices.scale(xScale.toFloat(), yScale.toFloat(), 1.0F) + EntityRenderer.renderEntity( + entity!!, + context, + 0, 0, + (mouseX - point.x) * xScale, + (mouseY - point.y) * yScale) + } } catch (ex: Exception) { ErrorUtil.softError("Failed to render constructed entity: $entity", ex) hasErrored = true + } finally { + context.matrices.pop() } if (hasErrored) { - context.fill(point.x, point.y, point.x + 50, point.y + 80, 0xFFAA2222.toInt()) + context.fill(point.x, point.y, point.x + size.width.toInt(), point.y + size.height.toInt(), 0xFFAA2222.toInt()) } } + companion object { + val defaultSize = Dimension(50, 80) + } + override fun getBounds(): Rectangle { - return Rectangle(point, Dimension(50, 80)) + return Rectangle(point, size) } } diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt index 2805132..232f04f 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt @@ -1,6 +1,8 @@ package moe.nea.firmament.compat.rei.recipes import java.util.Optional +import me.shedaniel.math.Dimension +import me.shedaniel.math.FloatingDimension import me.shedaniel.math.Point import me.shedaniel.math.Rectangle import me.shedaniel.rei.api.client.gui.Renderer @@ -14,17 +16,27 @@ import me.shedaniel.rei.api.common.display.Display import me.shedaniel.rei.api.common.display.DisplaySerializer import me.shedaniel.rei.api.common.entry.EntryIngredient import me.shedaniel.rei.api.common.entry.EntryStack +import net.minecraft.entity.EntityType +import net.minecraft.entity.SpawnReason import net.minecraft.text.Text import net.minecraft.util.Identifier +import net.minecraft.village.VillagerProfession import moe.nea.firmament.Firmament +import moe.nea.firmament.compat.rei.EntityWidget import moe.nea.firmament.compat.rei.SBItemEntryDefinition +import moe.nea.firmament.gui.entity.EntityRenderer import moe.nea.firmament.repo.Reforge import moe.nea.firmament.repo.ReforgeStore import moe.nea.firmament.repo.RepoItemTypeCache import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.repo.SBItemStack +import moe.nea.firmament.util.AprilFoolsUtil +import moe.nea.firmament.util.FirmFormatters import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.gold import moe.nea.firmament.util.skyblock.ItemType +import moe.nea.firmament.util.skyblock.Rarity +import moe.nea.firmament.util.skyblock.SkyBlockItems import moe.nea.firmament.util.skyblockId import moe.nea.firmament.util.tr @@ -46,21 +58,44 @@ class SBReforgeRecipe( } override fun getIcon(): Renderer { - return SBItemEntryDefinition.getEntry(SkyblockId("REFORGE_ANVIL")) + return SBItemEntryDefinition.getEntry(SkyBlockItems.REFORGE_ANVIL) } override fun setupDisplay(display: SBReforgeRecipe, bounds: Rectangle): MutableList { val list = mutableListOf() list.add(Widgets.createRecipeBase(bounds)) // TODO: actual layout after christmas, probably - list.add(Widgets.createSlot(Point(bounds.minX + 10, bounds.centerY)) + list.add(Widgets.createSlot(Point(bounds.minX + 10, bounds.centerY - 9)) .markInput().entries(display.inputItems)) - val stoneSlot = Widgets.createSlot(Point(bounds.minX + 38, bounds.centerY)) - .markInput() - if (display.reforgeStone != null) - stoneSlot.entry(display.reforgeStone) - list.add(stoneSlot) - list.add(Widgets.createSlot(Point(bounds.minX + 38 + 18, bounds.centerY)) + if (display.reforgeStone != null) { + list.add(Widgets.createSlot(Point(bounds.minX + 10 + 24, bounds.centerY - 9 - 10)) + .markInput().entry(display.reforgeStone)) + list.add(Widgets.withTooltip( + Widgets.withTranslate(Widgets.wrapRenderer( + Rectangle(Point(bounds.minX + 10 + 24, bounds.centerY - 9 + 10), Dimension(18, 18)), + SBItemEntryDefinition.getEntry(SkyBlockItems.REFORGE_ANVIL)), 0.0, 0.0, 150.0), + Rarity.entries.mapNotNull { rarity -> + display.reforge.reforgeCosts?.get(rarity)?.let { rarity to it } + }.map { (rarity, cost) -> + Text.literal("") + .append(rarity.text) + .append(": ") + .append(Text.literal("${FirmFormatters.formatCommas(cost, 0)} Coins").gold()) + } + )) + } else { + val size = if (AprilFoolsUtil.isAprilFoolsDay) 1.2 else 0.6 + val dimension = + FloatingDimension(EntityWidget.defaultSize.width * size, EntityWidget.defaultSize.height * size) + list.add(EntityWidget( + EntityType.VILLAGER.create(EntityRenderer.fakeWorld, SpawnReason.COMMAND) + ?.also { it.villagerData = it.villagerData.withProfession(VillagerProfession.WEAPONSMITH) }, + Point(bounds.minX + 10 + 24 + 8 - dimension.width / 2, bounds.centerY - dimension.height / 2), + dimension + )) +// TODO: render a blacksmith entity or smth + } + list.add(Widgets.createSlot(Point(bounds.minX + 10 + 24 + 24, bounds.centerY - 9)) .markInput().entries(display.outputItems)) return list } @@ -106,6 +141,7 @@ class SBReforgeRecipe( when (it) { is Reforge.ReforgeEligibilityFilter.AllowsInternalName -> listOfNotNull(RepoManager.getNEUItem(it.internalName)) + is Reforge.ReforgeEligibilityFilter.AllowsItemType -> ReforgeStore.resolveItemType(it.itemType) .flatMap { -- cgit From c4997e21053c8671ed4c5474fb70df6ae58dae06 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Wed, 25 Dec 2024 16:55:33 +0100 Subject: feat: Add reforge recipes --- .../compat/rei/recipes/SBReforgeRecipe.kt | 47 +++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'src/compat/rei/java/moe') diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt index 232f04f..9c8d8f4 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt @@ -6,6 +6,7 @@ import me.shedaniel.math.FloatingDimension 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.Label 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 @@ -34,6 +35,7 @@ import moe.nea.firmament.util.AprilFoolsUtil import moe.nea.firmament.util.FirmFormatters import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.gold +import moe.nea.firmament.util.grey import moe.nea.firmament.util.skyblock.ItemType import moe.nea.firmament.util.skyblock.Rarity import moe.nea.firmament.util.skyblock.SkyBlockItems @@ -64,15 +66,15 @@ class SBReforgeRecipe( override fun setupDisplay(display: SBReforgeRecipe, bounds: Rectangle): MutableList { val list = mutableListOf() list.add(Widgets.createRecipeBase(bounds)) - // TODO: actual layout after christmas, probably - list.add(Widgets.createSlot(Point(bounds.minX + 10, bounds.centerY - 9)) - .markInput().entries(display.inputItems)) + val inputSlot = Widgets.createSlot(Point(bounds.minX + 10, bounds.centerY - 9)) + .markInput().entries(display.inputItems) + list.add(inputSlot) if (display.reforgeStone != null) { list.add(Widgets.createSlot(Point(bounds.minX + 10 + 24, bounds.centerY - 9 - 10)) .markInput().entry(display.reforgeStone)) list.add(Widgets.withTooltip( Widgets.withTranslate(Widgets.wrapRenderer( - Rectangle(Point(bounds.minX + 10 + 24, bounds.centerY - 9 + 10), Dimension(18, 18)), + Rectangle(Point(bounds.minX + 10 + 24, bounds.centerY - 9 + 10), Dimension(16, 16)), SBItemEntryDefinition.getEntry(SkyBlockItems.REFORGE_ANVIL)), 0.0, 0.0, 150.0), Rarity.entries.mapNotNull { rarity -> display.reforge.reforgeCosts?.get(rarity)?.let { rarity to it } @@ -87,16 +89,41 @@ class SBReforgeRecipe( val size = if (AprilFoolsUtil.isAprilFoolsDay) 1.2 else 0.6 val dimension = FloatingDimension(EntityWidget.defaultSize.width * size, EntityWidget.defaultSize.height * size) - list.add(EntityWidget( - EntityType.VILLAGER.create(EntityRenderer.fakeWorld, SpawnReason.COMMAND) - ?.also { it.villagerData = it.villagerData.withProfession(VillagerProfession.WEAPONSMITH) }, - Point(bounds.minX + 10 + 24 + 8 - dimension.width / 2, bounds.centerY - dimension.height / 2), - dimension + list.add(Widgets.withTooltip( + EntityWidget( + EntityType.VILLAGER.create(EntityRenderer.fakeWorld, SpawnReason.COMMAND) + ?.also { it.villagerData = it.villagerData.withProfession(VillagerProfession.WEAPONSMITH) }, + Point(bounds.minX + 10 + 24 + 8 - dimension.width / 2, bounds.centerY - dimension.height / 2), + dimension + ), + tr("firmament.recipecategory.reforge.basic", + "This is a basic reforge, available at the Blacksmith.").grey() )) -// TODO: render a blacksmith entity or smth } list.add(Widgets.createSlot(Point(bounds.minX + 10 + 24 + 24, bounds.centerY - 9)) .markInput().entries(display.outputItems)) + val statToLineMappings = mutableListOf>() + for ((i, statId) in display.reforge.statUniverse.withIndex()) { + val label = Widgets.createLabel( + Point(bounds.minX + 10 + 24 + 24 + 20, bounds.minY + 8 + i * 11), + SBItemStack.Companion.StatLine(SBItemStack.statIdToName(statId), null).reconstitute(7)) + .horizontalAlignment(Label.LEFT_ALIGNED) + statToLineMappings.add(statId to label) + list.add(label) + } + fun updateStatLines() { + val entry = inputSlot.currentEntry?.castValue() ?: return + val stats = display.reforge.reforgeStats?.get(entry.rarity) ?: mapOf() + for ((stat, label) in statToLineMappings) { + label.message = + SBItemStack.Companion.StatLine( + SBItemStack.statIdToName(stat), null, + valueNum = stats[stat] + ).reconstitute(7) + } + } + updateStatLines() + inputSlot.withEntriesListener { updateStatLines() } return list } } -- cgit