aboutsummaryrefslogtreecommitdiff
path: root/src/compat
diff options
context:
space:
mode:
Diffstat (limited to 'src/compat')
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt34
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt6
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt210
-rw-r--r--src/compat/yacl/java/YaclIntegration.kt29
4 files changed, 272 insertions, 7 deletions
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<Element> {
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/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)
}
@@ -91,6 +93,10 @@ class FirmamentReiPlugin : REIClientPlugin {
SBCraftingRecipe.Category.catIdentifier,
SkyblockCraftingRecipeDynamicGenerator)
registry.registerDisplayGenerator(
+ SBReforgeRecipe.catIdentifier,
+ SBReforgeRecipe.DynamicGenerator
+ )
+ registry.registerDisplayGenerator(
SBForgeRecipe.Category.categoryIdentifier,
SkyblockForgeRecipeDynamicGenerator)
registry.registerDisplayGenerator(
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..9c8d8f4
--- /dev/null
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBReforgeRecipe.kt
@@ -0,0 +1,210 @@
+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
+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
+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.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.grey
+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
+
+class SBReforgeRecipe(
+ val reforge: Reforge,
+ val limitToItem: SkyblockId?,
+) : Display {
+ companion object {
+ val catIdentifier = CategoryIdentifier.of<SBReforgeRecipe>(Firmament.MOD_ID, "reforge_recipe")
+ }
+
+ object Category : DisplayCategory<SBReforgeRecipe> {
+ override fun getCategoryIdentifier(): CategoryIdentifier<out SBReforgeRecipe> {
+ return catIdentifier
+ }
+
+ override fun getTitle(): Text {
+ return tr("firmament.recipecategory.reforge", "Reforge")
+ }
+
+ override fun getIcon(): Renderer {
+ return SBItemEntryDefinition.getEntry(SkyBlockItems.REFORGE_ANVIL)
+ }
+
+ override fun setupDisplay(display: SBReforgeRecipe, bounds: Rectangle): MutableList<Widget> {
+ val list = mutableListOf<Widget>()
+ list.add(Widgets.createRecipeBase(bounds))
+ 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(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 }
+ }.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(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()
+ ))
+ }
+ list.add(Widgets.createSlot(Point(bounds.minX + 10 + 24 + 24, bounds.centerY - 9))
+ .markInput().entries(display.outputItems))
+ val statToLineMappings = mutableListOf<Pair<String, Label>>()
+ 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<SBItemStack>() ?: 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
+ }
+ }
+
+ object DynamicGenerator : DynamicDisplayGenerator<SBReforgeRecipe> {
+ fun getRecipesForSBItemStack(item: SBItemStack): Optional<List<SBReforgeRecipe>> {
+ val reforgeRecipes = mutableListOf<SBReforgeRecipe>()
+ 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<List<SBReforgeRecipe>> {
+ if (entry.type != SBItemEntryDefinition.type) return Optional.empty()
+ val item = entry.castValue<SBItemStack>()
+ return getRecipesForSBItemStack(item)
+ }
+
+ override fun getUsageFor(entry: EntryStack<*>): Optional<List<SBReforgeRecipe>> {
+ if (entry.type != SBItemEntryDefinition.type) return Optional.empty()
+ val item = entry.castValue<SBItemStack>()
+ ReforgeStore.byReforgeStone[item.skyblockId]?.let { stoneReforge ->
+ return Optional.of(listOf(SBReforgeRecipe(stoneReforge, null)))
+ }
+ return getRecipesForSBItemStack(item)
+ }
+
+ override fun generate(builder: ViewSearchBuilder): Optional<List<SBReforgeRecipe>> {
+ // 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<EntryIngredient> {
+ return inputEntries
+ }
+
+ override fun getOutputEntries(): List<EntryIngredient> {
+ return outputEntries
+ }
+
+ override fun getCategoryIdentifier(): CategoryIdentifier<*> {
+ return catIdentifier
+ }
+
+ override fun getDisplayLocation(): Optional<Identifier> {
+ return Optional.empty()
+ }
+
+ override fun getSerializer(): DisplaySerializer<out Display>? {
+ return null
+ }
+}
diff --git a/src/compat/yacl/java/YaclIntegration.kt b/src/compat/yacl/java/YaclIntegration.kt
index 9aec501..45a0d02 100644
--- a/src/compat/yacl/java/YaclIntegration.kt
+++ b/src/compat/yacl/java/YaclIntegration.kt
@@ -11,9 +11,11 @@ import dev.isxander.yacl3.api.OptionGroup
import dev.isxander.yacl3.api.YetAnotherConfigLib
import dev.isxander.yacl3.api.controller.ControllerBuilder
import dev.isxander.yacl3.api.controller.DoubleSliderControllerBuilder
+import dev.isxander.yacl3.api.controller.EnumControllerBuilder
import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder
import dev.isxander.yacl3.api.controller.StringControllerBuilder
import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder
+import dev.isxander.yacl3.api.controller.ValueFormatter
import dev.isxander.yacl3.gui.YACLScreen
import dev.isxander.yacl3.gui.tab.ListHolderWidget
import kotlin.time.Duration
@@ -23,8 +25,10 @@ import net.minecraft.client.gui.Element
import net.minecraft.client.gui.screen.Screen
import net.minecraft.text.Text
import moe.nea.firmament.gui.config.BooleanHandler
+import moe.nea.firmament.gui.config.ChoiceHandler
import moe.nea.firmament.gui.config.ClickHandler
import moe.nea.firmament.gui.config.DurationHandler
+import moe.nea.firmament.gui.config.EnumRenderer
import moe.nea.firmament.gui.config.FirmamentConfigScreenProvider
import moe.nea.firmament.gui.config.HudMeta
import moe.nea.firmament.gui.config.HudMetaHandler
@@ -89,6 +93,10 @@ class YaclIntegration : FirmamentConfigScreenProvider {
}
.build()
+ is ChoiceHandler<*> -> return createDefaultBinding {
+ createChoiceBinding(handler as ChoiceHandler<*>, managedOption as ManagedOption<*>, it as Option<*>)
+ }.build()
+
is BooleanHandler -> return createDefaultBinding(TickBoxControllerBuilder::create).build()
is StringHandler -> return createDefaultBinding(StringControllerBuilder::create).build()
is IntegerHandler -> return createDefaultBinding {
@@ -114,6 +122,27 @@ class YaclIntegration : FirmamentConfigScreenProvider {
}
}
+ private enum class Sacrifice {}
+
+ private fun createChoiceBinding(
+ handler: ChoiceHandler<*>,
+ managedOption: ManagedOption<*>,
+ option: Option<*>
+ ): ControllerBuilder<Any> {
+ val b = EnumControllerBuilder.create(option as Option<Sacrifice>)
+ b.enumClass(handler.enumClass as Class<Sacrifice>)
+ /**
+ * This is a function with E to avoid realizing the Sacrifice outside of a `X<E>` wrapper.
+ */
+ fun <E : Enum<*>> makeValueFormatter(): ValueFormatter<E> {
+ return ValueFormatter<E> {
+ (handler.renderer as EnumRenderer<E>).getName(managedOption as ManagedOption<E>, it)
+ }
+ }
+ b.formatValue(makeValueFormatter())
+ return b as ControllerBuilder<Any>
+ }
+
fun buildConfig(): YetAnotherConfigLib {
return YetAnotherConfigLib.createBuilder()