WIP: Reforge Recipes
This commit is contained in:
@@ -1,19 +1,22 @@
|
|||||||
package moe.nea.firmament.compat.rei
|
package moe.nea.firmament.compat.rei
|
||||||
|
|
||||||
import me.shedaniel.math.Dimension
|
import me.shedaniel.math.Dimension
|
||||||
|
import me.shedaniel.math.FloatingDimension
|
||||||
import me.shedaniel.math.Point
|
import me.shedaniel.math.Point
|
||||||
import me.shedaniel.math.Rectangle
|
import me.shedaniel.math.Rectangle
|
||||||
import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds
|
import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds
|
||||||
import net.minecraft.client.gui.DrawContext
|
import net.minecraft.client.gui.DrawContext
|
||||||
import net.minecraft.client.gui.Drawable
|
|
||||||
import net.minecraft.client.gui.Element
|
import net.minecraft.client.gui.Element
|
||||||
import net.minecraft.client.gui.ParentElement
|
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
import moe.nea.firmament.gui.entity.EntityRenderer
|
import moe.nea.firmament.gui.entity.EntityRenderer
|
||||||
import moe.nea.firmament.util.ErrorUtil
|
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> {
|
override fun children(): List<Element> {
|
||||||
return emptyList()
|
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) {
|
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
try {
|
try {
|
||||||
if (!hasErrored)
|
context.matrices.push()
|
||||||
EntityRenderer.renderEntity(entity!!, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat())
|
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) {
|
} catch (ex: Exception) {
|
||||||
ErrorUtil.softError("Failed to render constructed entity: $entity", ex)
|
ErrorUtil.softError("Failed to render constructed entity: $entity", ex)
|
||||||
hasErrored = true
|
hasErrored = true
|
||||||
|
} finally {
|
||||||
|
context.matrices.pop()
|
||||||
}
|
}
|
||||||
if (hasErrored) {
|
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 {
|
override fun getBounds(): Rectangle {
|
||||||
return Rectangle(point, Dimension(50, 80))
|
return Rectangle(point, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package moe.nea.firmament.compat.rei.recipes
|
package moe.nea.firmament.compat.rei.recipes
|
||||||
|
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
import me.shedaniel.math.Dimension
|
||||||
|
import me.shedaniel.math.FloatingDimension
|
||||||
import me.shedaniel.math.Point
|
import me.shedaniel.math.Point
|
||||||
import me.shedaniel.math.Rectangle
|
import me.shedaniel.math.Rectangle
|
||||||
import me.shedaniel.rei.api.client.gui.Renderer
|
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.display.DisplaySerializer
|
||||||
import me.shedaniel.rei.api.common.entry.EntryIngredient
|
import me.shedaniel.rei.api.common.entry.EntryIngredient
|
||||||
import me.shedaniel.rei.api.common.entry.EntryStack
|
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.text.Text
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.village.VillagerProfession
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.compat.rei.EntityWidget
|
||||||
import moe.nea.firmament.compat.rei.SBItemEntryDefinition
|
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.Reforge
|
||||||
import moe.nea.firmament.repo.ReforgeStore
|
import moe.nea.firmament.repo.ReforgeStore
|
||||||
import moe.nea.firmament.repo.RepoItemTypeCache
|
import moe.nea.firmament.repo.RepoItemTypeCache
|
||||||
import moe.nea.firmament.repo.RepoManager
|
import moe.nea.firmament.repo.RepoManager
|
||||||
import moe.nea.firmament.repo.SBItemStack
|
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.SkyblockId
|
||||||
|
import moe.nea.firmament.util.gold
|
||||||
import moe.nea.firmament.util.skyblock.ItemType
|
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.skyblockId
|
||||||
import moe.nea.firmament.util.tr
|
import moe.nea.firmament.util.tr
|
||||||
|
|
||||||
@@ -46,21 +58,44 @@ class SBReforgeRecipe(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getIcon(): Renderer {
|
override fun getIcon(): Renderer {
|
||||||
return SBItemEntryDefinition.getEntry(SkyblockId("REFORGE_ANVIL"))
|
return SBItemEntryDefinition.getEntry(SkyBlockItems.REFORGE_ANVIL)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupDisplay(display: SBReforgeRecipe, bounds: Rectangle): MutableList<Widget> {
|
override fun setupDisplay(display: SBReforgeRecipe, bounds: Rectangle): MutableList<Widget> {
|
||||||
val list = mutableListOf<Widget>()
|
val list = mutableListOf<Widget>()
|
||||||
list.add(Widgets.createRecipeBase(bounds))
|
list.add(Widgets.createRecipeBase(bounds))
|
||||||
// TODO: actual layout after christmas, probably
|
// 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))
|
.markInput().entries(display.inputItems))
|
||||||
val stoneSlot = Widgets.createSlot(Point(bounds.minX + 38, bounds.centerY))
|
if (display.reforgeStone != null) {
|
||||||
.markInput()
|
list.add(Widgets.createSlot(Point(bounds.minX + 10 + 24, bounds.centerY - 9 - 10))
|
||||||
if (display.reforgeStone != null)
|
.markInput().entry(display.reforgeStone))
|
||||||
stoneSlot.entry(display.reforgeStone)
|
list.add(Widgets.withTooltip(
|
||||||
list.add(stoneSlot)
|
Widgets.withTranslate(Widgets.wrapRenderer(
|
||||||
list.add(Widgets.createSlot(Point(bounds.minX + 38 + 18, bounds.centerY))
|
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))
|
.markInput().entries(display.outputItems))
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
@@ -106,6 +141,7 @@ class SBReforgeRecipe(
|
|||||||
when (it) {
|
when (it) {
|
||||||
is Reforge.ReforgeEligibilityFilter.AllowsInternalName ->
|
is Reforge.ReforgeEligibilityFilter.AllowsInternalName ->
|
||||||
listOfNotNull(RepoManager.getNEUItem(it.internalName))
|
listOfNotNull(RepoManager.getNEUItem(it.internalName))
|
||||||
|
|
||||||
is Reforge.ReforgeEligibilityFilter.AllowsItemType ->
|
is Reforge.ReforgeEligibilityFilter.AllowsItemType ->
|
||||||
ReforgeStore.resolveItemType(it.itemType)
|
ReforgeStore.resolveItemType(it.itemType)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
|
|||||||
@@ -29,18 +29,7 @@ object ItemRarityCosmetics : FirmamentFeature {
|
|||||||
override val config: ManagedConfig
|
override val config: ManagedConfig
|
||||||
get() = TConfig
|
get() = TConfig
|
||||||
|
|
||||||
private val rarityToColor = mapOf(
|
private val rarityToColor = Rarity.colourMap.mapValues {
|
||||||
Rarity.COMMON to Formatting.WHITE,
|
|
||||||
Rarity.UNCOMMON to Formatting.GREEN,
|
|
||||||
Rarity.RARE to Formatting.BLUE,
|
|
||||||
Rarity.EPIC to Formatting.DARK_PURPLE,
|
|
||||||
Rarity.LEGENDARY to Formatting.GOLD,
|
|
||||||
Rarity.MYTHIC to Formatting.LIGHT_PURPLE,
|
|
||||||
Rarity.DIVINE to Formatting.AQUA,
|
|
||||||
Rarity.SPECIAL to Formatting.RED,
|
|
||||||
Rarity.VERY_SPECIAL to Formatting.RED,
|
|
||||||
Rarity.SUPREME to Formatting.DARK_RED,
|
|
||||||
).mapValues {
|
|
||||||
val c = Color(it.value.colorValue!!)
|
val c = Color(it.value.colorValue!!)
|
||||||
c.rgb
|
c.rgb
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,8 +111,9 @@ object EntityRenderer {
|
|||||||
renderContext: DrawContext,
|
renderContext: DrawContext,
|
||||||
posX: Int,
|
posX: Int,
|
||||||
posY: Int,
|
posY: Int,
|
||||||
mouseX: Float,
|
// TODO: Add width, height properties here
|
||||||
mouseY: Float
|
mouseX: Double,
|
||||||
|
mouseY: Double
|
||||||
) {
|
) {
|
||||||
var bottomOffset = 0.0F
|
var bottomOffset = 0.0F
|
||||||
var currentEntity = entity
|
var currentEntity = entity
|
||||||
@@ -148,15 +149,15 @@ object EntityRenderer {
|
|||||||
y2: Int,
|
y2: Int,
|
||||||
size: Float,
|
size: Float,
|
||||||
bottomOffset: Float,
|
bottomOffset: Float,
|
||||||
mouseX: Float,
|
mouseX: Double,
|
||||||
mouseY: Float,
|
mouseY: Double,
|
||||||
entity: LivingEntity
|
entity: LivingEntity
|
||||||
) {
|
) {
|
||||||
context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
|
context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
|
||||||
val centerX = (x1 + x2) / 2f
|
val centerX = (x1 + x2) / 2f
|
||||||
val centerY = (y1 + y2) / 2f
|
val centerY = (y1 + y2) / 2f
|
||||||
val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat()
|
val targetYaw = atan(((centerX - mouseX) / 40.0f)).toFloat()
|
||||||
val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat()
|
val targetPitch = atan(((centerY - mouseY) / 40.0f)).toFloat()
|
||||||
val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
|
val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
|
||||||
val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
|
val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
|
||||||
rotateToFaceTheFront.mul(rotateToFaceTheCamera)
|
rotateToFaceTheFront.mul(rotateToFaceTheCamera)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import moe.nea.firmament.util.TestUtil
|
|||||||
import moe.nea.firmament.util.directLiteralStringContent
|
import moe.nea.firmament.util.directLiteralStringContent
|
||||||
import moe.nea.firmament.util.mc.FirmamentDataComponentTypes
|
import moe.nea.firmament.util.mc.FirmamentDataComponentTypes
|
||||||
import moe.nea.firmament.util.mc.appendLore
|
import moe.nea.firmament.util.mc.appendLore
|
||||||
|
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||||
import moe.nea.firmament.util.mc.modifyLore
|
import moe.nea.firmament.util.mc.modifyLore
|
||||||
import moe.nea.firmament.util.mc.setCustomName
|
import moe.nea.firmament.util.mc.setCustomName
|
||||||
@@ -131,6 +132,7 @@ object ItemCache : IReloadable {
|
|||||||
val itemInstance =
|
val itemInstance =
|
||||||
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
|
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
|
||||||
itemInstance.loreAccordingToNbt = lore.map { un189Lore(it) }
|
itemInstance.loreAccordingToNbt = lore.map { un189Lore(it) }
|
||||||
|
itemInstance.displayNameAccordingToNbt = un189Lore(displayName)
|
||||||
val extraAttributes = oldItemTag.getCompound("tag").getCompound("ExtraAttributes")
|
val extraAttributes = oldItemTag.getCompound("tag").getCompound("ExtraAttributes")
|
||||||
if (extraAttributes != null)
|
if (extraAttributes != null)
|
||||||
itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes))
|
itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes))
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ data class Reforge(
|
|||||||
|
|
||||||
@Serializable(with = RarityMapped.Serializer::class)
|
@Serializable(with = RarityMapped.Serializer::class)
|
||||||
sealed interface RarityMapped<T> {
|
sealed interface RarityMapped<T> {
|
||||||
|
fun get(rarity: Rarity): T?
|
||||||
|
|
||||||
class Serializer<T>(
|
class Serializer<T>(
|
||||||
val values: KSerializer<T>
|
val values: KSerializer<T>
|
||||||
) : KSerializer<RarityMapped<T>> {
|
) : KSerializer<RarityMapped<T>> {
|
||||||
@@ -137,10 +139,18 @@ data class Reforge(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Direct<T>(val value: T) : RarityMapped<T>
|
data class Direct<T>(val value: T) : RarityMapped<T> {
|
||||||
|
override fun get(rarity: Rarity): T {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PerRarity<T>(val values: Map<Rarity, T>) : RarityMapped<T>
|
data class PerRarity<T>(val values: Map<Rarity, T>) : RarityMapped<T> {
|
||||||
|
override fun get(rarity: Rarity): T? {
|
||||||
|
return values[rarity]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,22 +9,31 @@ import net.minecraft.item.ItemStack
|
|||||||
import net.minecraft.network.RegistryByteBuf
|
import net.minecraft.network.RegistryByteBuf
|
||||||
import net.minecraft.network.codec.PacketCodec
|
import net.minecraft.network.codec.PacketCodec
|
||||||
import net.minecraft.network.codec.PacketCodecs
|
import net.minecraft.network.codec.PacketCodecs
|
||||||
|
import net.minecraft.text.Style
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.text.TextColor
|
||||||
import net.minecraft.util.Formatting
|
import net.minecraft.util.Formatting
|
||||||
import moe.nea.firmament.repo.ItemCache.asItemStack
|
import moe.nea.firmament.repo.ItemCache.asItemStack
|
||||||
import moe.nea.firmament.util.FirmFormatters
|
import moe.nea.firmament.util.FirmFormatters
|
||||||
import moe.nea.firmament.util.LegacyFormattingCode
|
import moe.nea.firmament.util.LegacyFormattingCode
|
||||||
import moe.nea.firmament.util.ReforgeId
|
import moe.nea.firmament.util.ReforgeId
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
import moe.nea.firmament.util.blue
|
||||||
|
import moe.nea.firmament.util.directLiteralStringContent
|
||||||
|
import moe.nea.firmament.util.extraAttributes
|
||||||
import moe.nea.firmament.util.getReforgeId
|
import moe.nea.firmament.util.getReforgeId
|
||||||
import moe.nea.firmament.util.getUpgradeStars
|
import moe.nea.firmament.util.getUpgradeStars
|
||||||
|
import moe.nea.firmament.util.grey
|
||||||
import moe.nea.firmament.util.mc.appendLore
|
import moe.nea.firmament.util.mc.appendLore
|
||||||
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
|
||||||
import moe.nea.firmament.util.petData
|
import moe.nea.firmament.util.petData
|
||||||
|
import moe.nea.firmament.util.prepend
|
||||||
import moe.nea.firmament.util.skyBlockId
|
import moe.nea.firmament.util.skyBlockId
|
||||||
import moe.nea.firmament.util.skyblock.ItemType
|
import moe.nea.firmament.util.skyblock.ItemType
|
||||||
|
import moe.nea.firmament.util.skyblock.Rarity
|
||||||
import moe.nea.firmament.util.skyblockId
|
import moe.nea.firmament.util.skyblockId
|
||||||
|
import moe.nea.firmament.util.useMatch
|
||||||
import moe.nea.firmament.util.withColor
|
import moe.nea.firmament.util.withColor
|
||||||
|
|
||||||
data class SBItemStack constructor(
|
data class SBItemStack constructor(
|
||||||
@@ -84,6 +93,117 @@ data class SBItemStack constructor(
|
|||||||
}
|
}
|
||||||
return SBItemStack(neuIngredient.skyblockId, neuIngredient.amount.toInt())
|
return SBItemStack(neuIngredient.skyblockId, neuIngredient.amount.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun appendEnhancedStats(
|
||||||
|
itemStack: ItemStack,
|
||||||
|
reforgeStats: Map<String, Double>,
|
||||||
|
buffKind: BuffKind,
|
||||||
|
) {
|
||||||
|
val namedReforgeStats = reforgeStats
|
||||||
|
.mapKeysTo(mutableMapOf()) { statIdToName(it.key) }
|
||||||
|
val loreMut = itemStack.loreAccordingToNbt.toMutableList()
|
||||||
|
var statBlockLastIndex = -1
|
||||||
|
for (i in loreMut.indices) {
|
||||||
|
val statLine = parseStatLine(loreMut[i])
|
||||||
|
if (statLine == null && statBlockLastIndex >= 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (statLine == null) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
statBlockLastIndex = i
|
||||||
|
val statBuff = namedReforgeStats.remove(statLine.statName) ?: continue
|
||||||
|
loreMut[i] = statLine.addStat(statBuff, buffKind).reconstitute()
|
||||||
|
}
|
||||||
|
if (namedReforgeStats.isNotEmpty() && statBlockLastIndex == -1) {
|
||||||
|
loreMut.add(0, Text.literal(""))
|
||||||
|
}
|
||||||
|
// If there is no stat block the statBlockLastIndex falls through to -1
|
||||||
|
// TODO: this is good enough for some items. some other items might have their stats at a different place.
|
||||||
|
for ((statName, statBuff) in namedReforgeStats) {
|
||||||
|
val statLine = StatLine(statName, null).addStat(statBuff, buffKind)
|
||||||
|
loreMut.add(statBlockLastIndex + 1, statLine.reconstitute())
|
||||||
|
}
|
||||||
|
itemStack.loreAccordingToNbt = loreMut
|
||||||
|
}
|
||||||
|
|
||||||
|
data class StatFormatting(
|
||||||
|
val postFix: String,
|
||||||
|
val color: Formatting,
|
||||||
|
)
|
||||||
|
|
||||||
|
val formattingOverrides = mapOf(
|
||||||
|
"Sea Creature Chance" to StatFormatting("%", Formatting.RED),
|
||||||
|
"Strength" to StatFormatting("", Formatting.RED),
|
||||||
|
"Damage" to StatFormatting("", Formatting.RED),
|
||||||
|
"Bonus Attack Speed" to StatFormatting("%", Formatting.RED),
|
||||||
|
"Shot Cooldown" to StatFormatting("s", Formatting.RED),
|
||||||
|
"Ability Damage" to StatFormatting("%", Formatting.RED),
|
||||||
|
"Crit Damage" to StatFormatting("%", Formatting.RED),
|
||||||
|
"Crit Chance" to StatFormatting("%", Formatting.RED),
|
||||||
|
"Trophy Fish Chance" to StatFormatting("%", Formatting.GREEN),
|
||||||
|
// TODO: add other types and make this a repo json
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
private val statLabelRegex = "(?<statName>.*): ".toPattern()
|
||||||
|
|
||||||
|
enum class BuffKind(
|
||||||
|
val color: Formatting,
|
||||||
|
val prefix: String,
|
||||||
|
val postFix: String,
|
||||||
|
) {
|
||||||
|
REFORGE(Formatting.BLUE, "(", ")"),
|
||||||
|
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
data class StatLine(
|
||||||
|
val statName: String,
|
||||||
|
val value: Text?,
|
||||||
|
val rest: List<Text> = listOf(),
|
||||||
|
val valueNum: Double? = value?.directLiteralStringContent?.trim(' ', '%', '+')?.toDoubleOrNull()
|
||||||
|
) {
|
||||||
|
fun addStat(amount: Double, buffKind: BuffKind): StatLine {
|
||||||
|
val formattedAmount = FirmFormatters.formatCommas(amount, 1, includeSign = true)
|
||||||
|
return copy(
|
||||||
|
valueNum = (valueNum ?: 0.0) + amount,
|
||||||
|
value = null,
|
||||||
|
rest = rest +
|
||||||
|
listOf(
|
||||||
|
Text.literal(
|
||||||
|
buffKind.prefix + formattedAmount +
|
||||||
|
statFormatting.postFix +
|
||||||
|
buffKind.postFix + " ")
|
||||||
|
.withColor(buffKind.color)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun formatValue() =
|
||||||
|
Text.literal(FirmFormatters.formatCommas(valueNum ?: 0.0, 1, includeSign = true) + statFormatting.postFix + " ")
|
||||||
|
.setStyle(Style.EMPTY.withColor(statFormatting.color))
|
||||||
|
|
||||||
|
val statFormatting = formattingOverrides[statName] ?: StatFormatting("", Formatting.GREEN)
|
||||||
|
fun reconstitute(): Text =
|
||||||
|
Text.literal("").setStyle(Style.EMPTY.withItalic(false))
|
||||||
|
.append(Text.literal("$statName: ").grey())
|
||||||
|
.append(value ?: formatValue())
|
||||||
|
.also { rest.forEach(it::append) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun statIdToName(statId: String): String {
|
||||||
|
return statId.split("_").joinToString(" ") {
|
||||||
|
it.replaceFirstChar { it.uppercaseChar() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseStatLine(line: Text): StatLine? {
|
||||||
|
val sibs = line.siblings
|
||||||
|
val stat = sibs.firstOrNull() ?: return null
|
||||||
|
if (stat.style.color != TextColor.fromFormatting(Formatting.GRAY)) return null
|
||||||
|
val statLabel = stat.directLiteralStringContent ?: return null
|
||||||
|
val statName = statLabelRegex.useMatch(statLabel) { group("statName") } ?: return null
|
||||||
|
return StatLine(statName, sibs[1], sibs.subList(2, sibs.size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(skyblockId: SkyblockId, petData: PetData) : this(
|
constructor(skyblockId: SkyblockId, petData: PetData) : this(
|
||||||
@@ -134,11 +254,19 @@ data class SBItemStack constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun appendReforgeStatsToLore(
|
private fun appendReforgeInfo(
|
||||||
itemStack: ItemStack,
|
itemStack: ItemStack,
|
||||||
) {
|
) {
|
||||||
val rarity = itemStack.rarity
|
val rarity = Rarity.fromItem(itemStack) ?: return
|
||||||
val lore = itemStack.loreAccordingToNbt
|
val reforgeId = this.reforge ?: return
|
||||||
|
val reforge = ReforgeStore.modifierLut[reforgeId] ?: return
|
||||||
|
val reforgeStats = reforge.reforgeStats?.get(rarity) ?: mapOf()
|
||||||
|
itemStack.displayNameAccordingToNbt = itemStack.displayNameAccordingToNbt.copy()
|
||||||
|
.prepend(Text.literal(reforge.reforgeName + " ").formatted(Rarity.colourMap[rarity] ?: Formatting.WHITE))
|
||||||
|
val data = itemStack.extraAttributes.copy()
|
||||||
|
data.putString("modifier", reforgeId.id)
|
||||||
|
itemStack.extraAttributes = data
|
||||||
|
appendEnhancedStats(itemStack, reforgeStats, BuffKind.REFORGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: avoid instantiating the item stack here
|
// TODO: avoid instantiating the item stack here
|
||||||
@@ -156,8 +284,8 @@ data class SBItemStack constructor(
|
|||||||
injectReplacementDataForPets(replacementData)
|
injectReplacementDataForPets(replacementData)
|
||||||
return@run neuItem.asItemStack(idHint = skyblockId, replacementData)
|
return@run neuItem.asItemStack(idHint = skyblockId, replacementData)
|
||||||
.copyWithCount(stackSize)
|
.copyWithCount(stackSize)
|
||||||
|
.also { appendReforgeInfo(it) }
|
||||||
.also { it.appendLore(extraLore) }
|
.also { it.appendLore(extraLore) }
|
||||||
.also { if (reforge != null) it.appendLore(listOf(Text.literal("Reforge: $reforge"))) } // TODO: use this for proper rendering
|
|
||||||
.also { enhanceStatsByStars(it, stars) }
|
.also { enhanceStatsByStars(it, stars) }
|
||||||
}
|
}
|
||||||
if (itemStack_ == null)
|
if (itemStack_ == null)
|
||||||
|
|||||||
10
src/main/kotlin/util/AprilFoolsUtil.kt
Normal file
10
src/main/kotlin/util/AprilFoolsUtil.kt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.Month
|
||||||
|
|
||||||
|
object AprilFoolsUtil {
|
||||||
|
val isAprilFoolsDay = LocalDateTime.now().let {
|
||||||
|
it.dayOfMonth == 1 && it.month == Month.APRIL
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,21 +15,25 @@ import net.minecraft.text.Text
|
|||||||
|
|
||||||
object FirmFormatters {
|
object FirmFormatters {
|
||||||
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): String {
|
fun formatCommas(long: Long, segments: Int = 3, includeSign: Boolean = false): String {
|
||||||
|
if (long < 0 && long != Long.MIN_VALUE) {
|
||||||
|
return "-" + formatCommas(-long, segments, false)
|
||||||
|
}
|
||||||
|
val prefix = if (includeSign) "+" else ""
|
||||||
val α = long / 1000
|
val α = long / 1000
|
||||||
if (α != 0L) {
|
if (α != 0L) {
|
||||||
return formatCommas(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0')
|
return prefix + formatCommas(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0')
|
||||||
}
|
}
|
||||||
return long.toString()
|
return prefix + long.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatCommas(float: Float, fractionalDigits: Int): String = formatCommas(float.toDouble(), fractionalDigits)
|
fun formatCommas(float: Float, fractionalDigits: Int): String = formatCommas(float.toDouble(), fractionalDigits)
|
||||||
fun formatCommas(double: Double, fractionalDigits: Int): String {
|
fun formatCommas(double: Double, fractionalDigits: Int, includeSign: Boolean = false): String {
|
||||||
val long = double.toLong()
|
val long = double.toLong()
|
||||||
val δ = (double - long).absoluteValue
|
val δ = (double - long).absoluteValue
|
||||||
val μ = pow(10, fractionalDigits)
|
val μ = pow(10, fractionalDigits)
|
||||||
val digits = (μ * δ).toInt().toString().padStart(fractionalDigits, '0').trimEnd('0')
|
val digits = (μ * δ).toInt().toString().padStart(fractionalDigits, '0').trimEnd('0')
|
||||||
return formatCommas(long) + (if (digits.isEmpty()) "" else ".$digits")
|
return formatCommas(long, includeSign = includeSign) + (if (digits.isEmpty()) "" else ".$digits")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatDistance(distance: Double): String {
|
fun formatDistance(distance: Double): String {
|
||||||
|
|||||||
@@ -106,7 +106,10 @@ data class HypixelPetInfo(
|
|||||||
|
|
||||||
private val jsonparser = Json { ignoreUnknownKeys = true }
|
private val jsonparser = Json { ignoreUnknownKeys = true }
|
||||||
|
|
||||||
val ItemStack.extraAttributes: NbtCompound
|
var ItemStack.extraAttributes: NbtCompound
|
||||||
|
set(value) {
|
||||||
|
set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(value))
|
||||||
|
}
|
||||||
get() {
|
get() {
|
||||||
val customData = get(DataComponentTypes.CUSTOM_DATA) ?: run {
|
val customData = get(DataComponentTypes.CUSTOM_DATA) ?: run {
|
||||||
val component = NbtComponent.of(NbtCompound())
|
val component = NbtComponent.of(NbtCompound())
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import net.minecraft.component.type.LoreComponent
|
|||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
|
||||||
var ItemStack.loreAccordingToNbt
|
var ItemStack.loreAccordingToNbt: List<Text>
|
||||||
get() = get(DataComponentTypes.LORE)?.lines ?: listOf()
|
get() = get(DataComponentTypes.LORE)?.lines ?: listOf()
|
||||||
set(value) {
|
set(value) {
|
||||||
set(DataComponentTypes.LORE, LoreComponent(value))
|
set(DataComponentTypes.LORE, LoreComponent(value))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
|||||||
import kotlinx.serialization.encoding.Decoder
|
import kotlinx.serialization.encoding.Decoder
|
||||||
import kotlinx.serialization.encoding.Encoder
|
import kotlinx.serialization.encoding.Encoder
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.text.Style
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.Formatting
|
||||||
import moe.nea.firmament.util.StringUtil.words
|
import moe.nea.firmament.util.StringUtil.words
|
||||||
import moe.nea.firmament.util.collections.lastNotNullOfOrNull
|
import moe.nea.firmament.util.collections.lastNotNullOfOrNull
|
||||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||||
@@ -46,10 +48,23 @@ enum class Rarity(vararg altNames: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val names = setOf(name) + altNames
|
val names = setOf(name) + altNames
|
||||||
|
val text: Text get() = Text.literal(name).setStyle(Style.EMPTY.withColor(colourMap[this]))
|
||||||
val neuRepoRarity: RepoRarity? = RepoRarity.entries.find { it.name == name }
|
val neuRepoRarity: RepoRarity? = RepoRarity.entries.find { it.name == name }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
// TODO: inline those formattings as fields
|
||||||
|
val colourMap = mapOf(
|
||||||
|
Rarity.COMMON to Formatting.WHITE,
|
||||||
|
Rarity.UNCOMMON to Formatting.GREEN,
|
||||||
|
Rarity.RARE to Formatting.BLUE,
|
||||||
|
Rarity.EPIC to Formatting.DARK_PURPLE,
|
||||||
|
Rarity.LEGENDARY to Formatting.GOLD,
|
||||||
|
Rarity.MYTHIC to Formatting.LIGHT_PURPLE,
|
||||||
|
Rarity.DIVINE to Formatting.AQUA,
|
||||||
|
Rarity.SPECIAL to Formatting.RED,
|
||||||
|
Rarity.VERY_SPECIAL to Formatting.RED,
|
||||||
|
Rarity.SUPREME to Formatting.DARK_RED,
|
||||||
|
)
|
||||||
val byName = entries.flatMap { en -> en.names.map { it to en } }.toMap()
|
val byName = entries.flatMap { en -> en.names.map { it to en } }.toMap()
|
||||||
val fromNeuRepo = entries.associateBy { it.neuRepoRarity }
|
val fromNeuRepo = entries.associateBy { it.neuRepoRarity }
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ object SkyBlockItems {
|
|||||||
val ENCHANTED_DIAMOND = SkyblockId("ENCHANTED_DIAMOND")
|
val ENCHANTED_DIAMOND = SkyblockId("ENCHANTED_DIAMOND")
|
||||||
val DIAMOND = SkyblockId("DIAMOND")
|
val DIAMOND = SkyblockId("DIAMOND")
|
||||||
val ANCESTRAL_SPADE = SkyblockId("ANCESTRAL_SPADE")
|
val ANCESTRAL_SPADE = SkyblockId("ANCESTRAL_SPADE")
|
||||||
|
val REFORGE_ANVIL = SkyblockId("REFORGE_ANVIL")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ fun MutableText.darkGreen() = withColor(Formatting.DARK_GREEN)
|
|||||||
fun MutableText.purple() = withColor(Formatting.DARK_PURPLE)
|
fun MutableText.purple() = withColor(Formatting.DARK_PURPLE)
|
||||||
fun MutableText.pink() = withColor(Formatting.LIGHT_PURPLE)
|
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.grey() = withColor(Formatting.GRAY)
|
fun MutableText.grey() = withColor(Formatting.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)
|
||||||
@@ -146,6 +147,11 @@ fun MutableText.clickCommand(command: String): MutableText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun MutableText.prepend(text: Text): MutableText {
|
||||||
|
siblings.addFirst(text)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun Text.transformEachRecursively(function: (Text) -> Text): Text {
|
fun Text.transformEachRecursively(function: (Text) -> Text): Text {
|
||||||
val c = this.content
|
val c = this.content
|
||||||
if (c is TranslatableTextContent) {
|
if (c is TranslatableTextContent) {
|
||||||
|
|||||||
Reference in New Issue
Block a user