feat: Add npc shop recipes
This commit is contained in:
@@ -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.SBKatRecipe
|
||||||
import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe
|
import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe
|
||||||
import moe.nea.firmament.compat.rei.recipes.SBReforgeRecipe
|
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.events.HandledScreenPushREIEvent
|
||||||
import moe.nea.firmament.features.inventory.CraftingOverlay
|
import moe.nea.firmament.features.inventory.CraftingOverlay
|
||||||
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
|
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
|
||||||
@@ -81,6 +82,7 @@ class FirmamentReiPlugin : REIClientPlugin {
|
|||||||
registry.add(SBKatRecipe.Category)
|
registry.add(SBKatRecipe.Category)
|
||||||
registry.add(SBReforgeRecipe.Category)
|
registry.add(SBReforgeRecipe.Category)
|
||||||
registry.add(SBEssenceUpgradeRecipe.Category)
|
registry.add(SBEssenceUpgradeRecipe.Category)
|
||||||
|
registry.add(SBShopRecipe.Category)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerExclusionZones(zones: ExclusionZones) {
|
override fun registerExclusionZones(zones: ExclusionZones) {
|
||||||
@@ -102,6 +104,9 @@ class FirmamentReiPlugin : REIClientPlugin {
|
|||||||
registry.registerDisplayGenerator(
|
registry.registerDisplayGenerator(
|
||||||
SBMobDropRecipe.Category.categoryIdentifier,
|
SBMobDropRecipe.Category.categoryIdentifier,
|
||||||
SkyblockMobDropRecipeDynamicGenerator)
|
SkyblockMobDropRecipeDynamicGenerator)
|
||||||
|
registry.registerDisplayGenerator(
|
||||||
|
SBShopRecipe.Category.categoryIdentifier,
|
||||||
|
SkyblockShopRecipeDynamicGenerator)
|
||||||
registry.registerDisplayGenerator(
|
registry.registerDisplayGenerator(
|
||||||
SBKatRecipe.Category.categoryIdentifier,
|
SBKatRecipe.Category.categoryIdentifier,
|
||||||
SkyblockKatRecipeDynamicGenerator)
|
SkyblockKatRecipeDynamicGenerator)
|
||||||
|
|||||||
@@ -18,10 +18,13 @@ import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback
|
|||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.DrawContext
|
import net.minecraft.client.gui.DrawContext
|
||||||
import net.minecraft.item.tooltip.TooltipType
|
import net.minecraft.item.tooltip.TooltipType
|
||||||
|
import net.minecraft.text.Text
|
||||||
import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry
|
import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry
|
||||||
import moe.nea.firmament.events.ItemTooltipEvent
|
import moe.nea.firmament.events.ItemTooltipEvent
|
||||||
import moe.nea.firmament.repo.SBItemStack
|
import moe.nea.firmament.repo.SBItemStack
|
||||||
import moe.nea.firmament.util.ErrorUtil
|
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.displayNameAccordingToNbt
|
||||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
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.translate(bounds.centerX.toFloat(), bounds.centerY.toFloat(), 0F)
|
||||||
context.matrices.scale(bounds.width.toFloat() / 16F, bounds.height.toFloat() / 16F, 1f)
|
context.matrices.scale(bounds.width.toFloat() / 16F, bounds.height.toFloat() / 16F, 1f)
|
||||||
val item = entry.asItemEntry().value
|
val item = entry.asItemEntry().value
|
||||||
context.drawItemWithoutEntity(item, -8, -8, )
|
context.drawItemWithoutEntity(item, -8, -8)
|
||||||
context.drawStackOverlay(minecraft.textRenderer, 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()
|
context.matrices.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +77,8 @@ object NEUItemEntryRenderer : EntryRenderer<SBItemStack> {
|
|||||||
lore
|
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
|
// TODO: tags aren't sent as early now so some tooltip components that use tags will crash the game
|
||||||
// stack.getTooltip(
|
// stack.getTooltip(
|
||||||
// Item.TooltipContext.create(
|
// Item.TooltipContext.create(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import io.github.moulberry.repo.data.NEUCraftingRecipe
|
|||||||
import io.github.moulberry.repo.data.NEUForgeRecipe
|
import io.github.moulberry.repo.data.NEUForgeRecipe
|
||||||
import io.github.moulberry.repo.data.NEUKatUpgradeRecipe
|
import io.github.moulberry.repo.data.NEUKatUpgradeRecipe
|
||||||
import io.github.moulberry.repo.data.NEUMobDropRecipe
|
import io.github.moulberry.repo.data.NEUMobDropRecipe
|
||||||
|
import io.github.moulberry.repo.data.NEUNpcShopRecipe
|
||||||
import io.github.moulberry.repo.data.NEURecipe
|
import io.github.moulberry.repo.data.NEURecipe
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator
|
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.SBForgeRecipe
|
||||||
import moe.nea.firmament.compat.rei.recipes.SBKatRecipe
|
import moe.nea.firmament.compat.rei.recipes.SBKatRecipe
|
||||||
import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe
|
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.EssenceRecipeProvider
|
||||||
import moe.nea.firmament.repo.RepoManager
|
import moe.nea.firmament.repo.RepoManager
|
||||||
import moe.nea.firmament.repo.SBItemStack
|
import moe.nea.firmament.repo.SBItemStack
|
||||||
@@ -28,7 +30,8 @@ val SkyblockForgeRecipeDynamicGenerator =
|
|||||||
|
|
||||||
val SkyblockMobDropRecipeDynamicGenerator =
|
val SkyblockMobDropRecipeDynamicGenerator =
|
||||||
neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) }
|
neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) }
|
||||||
|
val SkyblockShopRecipeDynamicGenerator =
|
||||||
|
neuDisplayGenerator<SBShopRecipe, NEUNpcShopRecipe> { SBShopRecipe(it) }
|
||||||
val SkyblockKatRecipeDynamicGenerator =
|
val SkyblockKatRecipeDynamicGenerator =
|
||||||
neuDisplayGenerator<SBKatRecipe, NEUKatUpgradeRecipe> { SBKatRecipe(it) }
|
neuDisplayGenerator<SBKatRecipe, NEUKatUpgradeRecipe> { SBKatRecipe(it) }
|
||||||
val SkyblockEssenceRecipeDynamicGenerator =
|
val SkyblockEssenceRecipeDynamicGenerator =
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class SBCraftingRecipe(override val neuRecipe: NEUCraftingRecipe) : SBRecipe() {
|
|||||||
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.catIdentifier
|
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.catIdentifier
|
||||||
|
|
||||||
object Category : DisplayCategory<SBCraftingRecipe> {
|
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 getCategoryIdentifier(): CategoryIdentifier<out SBCraftingRecipe> = catIdentifier
|
||||||
|
|
||||||
override fun getTitle(): Text = Text.literal("SkyBlock Crafting")
|
override fun getTitle(): Text = Text.literal("SkyBlock Crafting")
|
||||||
|
|||||||
@@ -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.gui.widgets.Widgets
|
||||||
import me.shedaniel.rei.api.client.registry.display.DisplayCategory
|
import me.shedaniel.rei.api.client.registry.display.DisplayCategory
|
||||||
import me.shedaniel.rei.api.common.category.CategoryIdentifier
|
import me.shedaniel.rei.api.common.category.CategoryIdentifier
|
||||||
import me.shedaniel.rei.api.common.util.EntryStacks
|
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
@@ -41,6 +40,7 @@ class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() {
|
|||||||
Text.stringifiedTranslatable("firmament.recipe.forge.time",
|
Text.stringifiedTranslatable("firmament.recipe.forge.time",
|
||||||
display.neuRecipe.duration.seconds)))
|
display.neuRecipe.duration.seconds)))
|
||||||
val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
|
val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
|
||||||
|
add(Widgets.createBurningFire(ingredientsCenter).animationDurationTicks(25.0))
|
||||||
val count = display.neuRecipe.inputs.size
|
val count = display.neuRecipe.inputs.size
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
add(
|
add(
|
||||||
|
|||||||
@@ -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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,8 +2,10 @@ package moe.nea.firmament.repo
|
|||||||
|
|
||||||
import io.github.moulberry.repo.IReloadable
|
import io.github.moulberry.repo.IReloadable
|
||||||
import io.github.moulberry.repo.NEURepository
|
import io.github.moulberry.repo.NEURepository
|
||||||
|
import io.github.moulberry.repo.data.NEUNpcShopRecipe
|
||||||
import io.github.moulberry.repo.data.NEURecipe
|
import io.github.moulberry.repo.data.NEURecipe
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
import moe.nea.firmament.util.skyblockId
|
||||||
|
|
||||||
class BetterRepoRecipeCache(vararg val extraProviders: ExtraRecipeProvider) : IReloadable {
|
class BetterRepoRecipeCache(vararg val extraProviders: ExtraRecipeProvider) : IReloadable {
|
||||||
var usages: Map<SkyblockId, Set<NEURecipe>> = mapOf()
|
var usages: Map<SkyblockId, Set<NEURecipe>> = mapOf()
|
||||||
@@ -17,6 +19,9 @@ class BetterRepoRecipeCache(vararg val extraProviders: ExtraRecipeProvider) : IR
|
|||||||
.flatMap { it.recipes }
|
.flatMap { it.recipes }
|
||||||
(baseRecipes + extraProviders.flatMap { it.provideExtraRecipes() })
|
(baseRecipes + extraProviders.flatMap { it.provideExtraRecipes() })
|
||||||
.forEach { recipe ->
|
.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.allInputs.forEach { usages.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
|
||||||
recipe.allOutputs.forEach { recipes.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
|
recipe.allOutputs.forEach { recipes.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,39 @@ import kotlin.io.path.isReadable
|
|||||||
import kotlin.io.path.isRegularFile
|
import kotlin.io.path.isRegularFile
|
||||||
import kotlin.io.path.listDirectoryEntries
|
import kotlin.io.path.listDirectoryEntries
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.roundToInt
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
|
||||||
object FirmFormatters {
|
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(int: Int, segments: Int = 3): String = formatCommas(int.toLong(), segments)
|
||||||
fun formatCommas(long: Long, segments: Int = 3, includeSign: Boolean = false): String {
|
fun formatCommas(long: Long, segments: Int = 3, includeSign: Boolean = false): String {
|
||||||
if (long < 0 && long != Long.MIN_VALUE) {
|
if (long < 0 && long != Long.MIN_VALUE) {
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ fun MutableText.pink() = withColor(Formatting.LIGHT_PURPLE)
|
|||||||
fun MutableText.yellow() = withColor(Formatting.YELLOW)
|
fun MutableText.yellow() = withColor(Formatting.YELLOW)
|
||||||
fun MutableText.gold() = withColor(Formatting.GOLD)
|
fun MutableText.gold() = withColor(Formatting.GOLD)
|
||||||
fun MutableText.grey() = withColor(Formatting.GRAY)
|
fun MutableText.grey() = withColor(Formatting.GRAY)
|
||||||
|
fun MutableText.darkGrey() = withColor(Formatting.DARK_GRAY)
|
||||||
fun MutableText.red() = withColor(Formatting.RED)
|
fun MutableText.red() = withColor(Formatting.RED)
|
||||||
fun MutableText.white() = withColor(Formatting.WHITE)
|
fun MutableText.white() = withColor(Formatting.WHITE)
|
||||||
fun MutableText.bold(): MutableText = styled { it.withBold(true) }
|
fun MutableText.bold(): MutableText = styled { it.withBold(true) }
|
||||||
|
|||||||
Reference in New Issue
Block a user