Skip to content

Commit

Permalink
feat: Add npc shop recipes
Browse files Browse the repository at this point in the history
nea89o committed Jan 21, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent bb56231 commit 2a3a4c0
Showing 9 changed files with 117 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ 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.compat.rei.recipes.SBShopRecipe
import moe.nea.firmament.events.HandledScreenPushREIEvent
import moe.nea.firmament.features.inventory.CraftingOverlay
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
@@ -81,6 +82,7 @@ class FirmamentReiPlugin : REIClientPlugin {
registry.add(SBKatRecipe.Category)
registry.add(SBReforgeRecipe.Category)
registry.add(SBEssenceUpgradeRecipe.Category)
registry.add(SBShopRecipe.Category)
}

override fun registerExclusionZones(zones: ExclusionZones) {
@@ -102,6 +104,9 @@ class FirmamentReiPlugin : REIClientPlugin {
registry.registerDisplayGenerator(
SBMobDropRecipe.Category.categoryIdentifier,
SkyblockMobDropRecipeDynamicGenerator)
registry.registerDisplayGenerator(
SBShopRecipe.Category.categoryIdentifier,
SkyblockShopRecipeDynamicGenerator)
registry.registerDisplayGenerator(
SBKatRecipe.Category.categoryIdentifier,
SkyblockKatRecipeDynamicGenerator)
Original file line number Diff line number Diff line change
@@ -18,10 +18,13 @@ import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.item.tooltip.TooltipType
import net.minecraft.text.Text
import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry
import moe.nea.firmament.events.ItemTooltipEvent
import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.darkGrey
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt

@@ -40,8 +43,12 @@ object NEUItemEntryRenderer : EntryRenderer<SBItemStack> {
context.matrices.translate(bounds.centerX.toFloat(), bounds.centerY.toFloat(), 0F)
context.matrices.scale(bounds.width.toFloat() / 16F, bounds.height.toFloat() / 16F, 1f)
val item = entry.asItemEntry().value
context.drawItemWithoutEntity(item, -8, -8, )
context.drawStackOverlay(minecraft.textRenderer, item, -8, -8)
context.drawItemWithoutEntity(item, -8, -8)
context.drawStackOverlay(minecraft.textRenderer, item, -8, -8,
if (entry.value.getStackSize() > 1000) FirmFormatters.shortFormat(entry.value.getStackSize()
.toDouble())
else null
)
context.matrices.pop()
}

@@ -70,6 +77,8 @@ object NEUItemEntryRenderer : EntryRenderer<SBItemStack> {
lore
))
}
if (entry.value.getStackSize() > 1000 && lore.isNotEmpty())
lore.add(1, Text.literal("${entry.value.getStackSize()}x").darkGrey())
// TODO: tags aren't sent as early now so some tooltip components that use tags will crash the game
// stack.getTooltip(
// Item.TooltipContext.create(
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import io.github.moulberry.repo.data.NEUCraftingRecipe
import io.github.moulberry.repo.data.NEUForgeRecipe
import io.github.moulberry.repo.data.NEUKatUpgradeRecipe
import io.github.moulberry.repo.data.NEUMobDropRecipe
import io.github.moulberry.repo.data.NEUNpcShopRecipe
import io.github.moulberry.repo.data.NEURecipe
import java.util.Optional
import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator
@@ -15,6 +16,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.SBShopRecipe
import moe.nea.firmament.repo.EssenceRecipeProvider
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.repo.SBItemStack
@@ -28,7 +30,8 @@ val SkyblockForgeRecipeDynamicGenerator =

val SkyblockMobDropRecipeDynamicGenerator =
neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) }

val SkyblockShopRecipeDynamicGenerator =
neuDisplayGenerator<SBShopRecipe, NEUNpcShopRecipe> { SBShopRecipe(it) }
val SkyblockKatRecipeDynamicGenerator =
neuDisplayGenerator<SBKatRecipe, NEUKatUpgradeRecipe> { SBKatRecipe(it) }
val SkyblockEssenceRecipeDynamicGenerator =
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ class SBCraftingRecipe(override val neuRecipe: NEUCraftingRecipe) : SBRecipe() {
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.catIdentifier

object Category : DisplayCategory<SBCraftingRecipe> {
val catIdentifier = CategoryIdentifier.of<SBCraftingRecipe>(Firmament.MOD_ID, "crafing_recipe")
val catIdentifier = CategoryIdentifier.of<SBCraftingRecipe>(Firmament.MOD_ID, "crafting_recipe")
override fun getCategoryIdentifier(): CategoryIdentifier<out SBCraftingRecipe> = catIdentifier

override fun getTitle(): Text = Text.literal("SkyBlock Crafting")
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ 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.EntryStacks
import kotlin.math.cos
import kotlin.math.sin
import kotlin.time.Duration.Companion.seconds
@@ -41,6 +40,7 @@ class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() {
Text.stringifiedTranslatable("firmament.recipe.forge.time",
display.neuRecipe.duration.seconds)))
val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
add(Widgets.createBurningFire(ingredientsCenter).animationDurationTicks(25.0))
val count = display.neuRecipe.inputs.size
if (count == 1) {
add(
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package moe.nea.firmament.compat.rei.recipes

import io.github.moulberry.repo.data.NEUNpcShopRecipe
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.entry.EntryIngredient
import net.minecraft.item.Items
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.compat.rei.SBItemEntryDefinition
import moe.nea.firmament.util.skyblockId

class SBShopRecipe(override val neuRecipe: NEUNpcShopRecipe) : SBRecipe() {
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.catIdentifier
val merchant = SBItemEntryDefinition.getEntry(neuRecipe.isSoldBy.skyblockId)
override fun getInputEntries(): List<EntryIngredient> {
return listOf(EntryIngredient.of(merchant)) + super.getInputEntries()
}

object Category : DisplayCategory<SBShopRecipe> {
val catIdentifier = CategoryIdentifier.of<SBShopRecipe>(Firmament.MOD_ID, "npc_shopping")
override fun getCategoryIdentifier(): CategoryIdentifier<SBShopRecipe> = catIdentifier

override fun getTitle(): Text = Text.literal("SkyBlock NPC Shopping")

override fun getIcon(): Renderer = SBItemEntryDefinition.getPassthrough(Items.EMERALD)
override fun setupDisplay(display: SBShopRecipe, bounds: Rectangle): List<Widget> {
val point = Point(bounds.centerX, bounds.centerY)
return buildList {
add(Widgets.createRecipeBase(bounds))
add(Widgets.createSlot(Point(point.x - 2 - 18 / 2, point.y - 18 - 6))
.unmarkInputOrOutput()
.entry(display.merchant)
.disableBackground())
add(Widgets.createArrow(Point(point.x - 2 - 24 / 2, point.y - 6)))
val cost = display.neuRecipe.cost
for ((i, item) in cost.withIndex()) {
add(Widgets.createSlot(Point(
point.x - 14 - 18,
point.y + i * 18 - 18 * cost.size / 2))
.entry(SBItemEntryDefinition.getEntry(item))
.markInput())
// TODO: fix frame clipping
}
add(Widgets.createResultSlotBackground(Point(point.x + 18, point.y - 18 / 2)))
add(
Widgets.createSlot(Point(point.x + 18, point.y - 18 / 2))
.entry(SBItemEntryDefinition.getEntry(display.neuRecipe.result))
.disableBackground().markOutput()
)
}
}

}

}
5 changes: 5 additions & 0 deletions src/main/kotlin/repo/BetterRepoRecipeCache.kt
Original file line number Diff line number Diff line change
@@ -2,8 +2,10 @@ package moe.nea.firmament.repo

import io.github.moulberry.repo.IReloadable
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEUNpcShopRecipe
import io.github.moulberry.repo.data.NEURecipe
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.skyblockId

class BetterRepoRecipeCache(vararg val extraProviders: ExtraRecipeProvider) : IReloadable {
var usages: Map<SkyblockId, Set<NEURecipe>> = mapOf()
@@ -17,6 +19,9 @@ class BetterRepoRecipeCache(vararg val extraProviders: ExtraRecipeProvider) : IR
.flatMap { it.recipes }
(baseRecipes + extraProviders.flatMap { it.provideExtraRecipes() })
.forEach { recipe ->
if (recipe is NEUNpcShopRecipe) {
usages.getOrPut(recipe.isSoldBy.skyblockId, ::mutableSetOf).add(recipe)
}
recipe.allInputs.forEach { usages.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
recipe.allOutputs.forEach { recipes.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
}
28 changes: 28 additions & 0 deletions src/main/kotlin/util/FirmFormatters.kt
Original file line number Diff line number Diff line change
@@ -9,11 +9,39 @@ import kotlin.io.path.isReadable
import kotlin.io.path.isRegularFile
import kotlin.io.path.listDirectoryEntries
import kotlin.math.absoluteValue
import kotlin.math.roundToInt
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import net.minecraft.text.Text

object FirmFormatters {

private inline fun shortIf(
value: Double, breakpoint: Double, char: String,
return_: (String) -> Nothing
) {
if (value >= breakpoint) {
val broken = (value / breakpoint * 10).roundToInt()
if (broken > 99)
return_((broken / 10).toString() + char)
val decimals = broken.toString()
decimals.singleOrNull()?.let {
return_("0.$it$char")
}
return_("${decimals[0]}.${decimals[1]}$char")
}
}

fun shortFormat(double: Double): String {
if (double < 0) return "-" + shortFormat(-double)
shortIf(double, 1_000_000_000_000.0, "t") { return it }
shortIf(double, 1_000_000_000.0, "b") { return it }
shortIf(double, 1_000_000.0, "m") { return it }
shortIf(double, 1_000.0, "k") { return it }
shortIf(double, 1.0, "") { return it }
return double.toString()
}

fun formatCommas(int: Int, segments: Int = 3): String = formatCommas(int.toLong(), segments)
fun formatCommas(long: Long, segments: Int = 3, includeSign: Boolean = false): String {
if (long < 0 && long != Long.MIN_VALUE) {
1 change: 1 addition & 0 deletions src/main/kotlin/util/textutil.kt
Original file line number Diff line number Diff line change
@@ -122,6 +122,7 @@ fun MutableText.pink() = withColor(Formatting.LIGHT_PURPLE)
fun MutableText.yellow() = withColor(Formatting.YELLOW)
fun MutableText.gold() = withColor(Formatting.GOLD)
fun MutableText.grey() = withColor(Formatting.GRAY)
fun MutableText.darkGrey() = withColor(Formatting.DARK_GRAY)
fun MutableText.red() = withColor(Formatting.RED)
fun MutableText.white() = withColor(Formatting.WHITE)
fun MutableText.bold(): MutableText = styled { it.withBold(true) }

0 comments on commit 2a3a4c0

Please sign in to comment.