aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-12-25 16:15:20 +0100
committerLinnea Gräf <nea@nea.moe>2024-12-25 16:15:20 +0100
commitddebaf47900dfab41590c97c202984142ae5b9f6 (patch)
tree498859e320b19d3bc7559f5585174afb78e132b4
parente16c60169bf192b79991176b5f9cee66b5b16e7d (diff)
downloadFirmament-ddebaf47900dfab41590c97c202984142ae5b9f6.tar.gz
Firmament-ddebaf47900dfab41590c97c202984142ae5b9f6.tar.bz2
Firmament-ddebaf47900dfab41590c97c202984142ae5b9f6.zip
WIP: Reforge Recipes
-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/recipes/SBReforgeRecipe.kt52
-rw-r--r--src/main/kotlin/features/inventory/ItemRarityCosmetics.kt13
-rw-r--r--src/main/kotlin/gui/entity/EntityRenderer.kt13
-rw-r--r--src/main/kotlin/repo/ItemCache.kt2
-rw-r--r--src/main/kotlin/repo/Reforge.kt14
-rw-r--r--src/main/kotlin/repo/SBItemStack.kt136
-rw-r--r--src/main/kotlin/util/AprilFoolsUtil.kt10
-rw-r--r--src/main/kotlin/util/FirmFormatters.kt14
-rw-r--r--src/main/kotlin/util/SkyblockId.kt5
-rw-r--r--src/main/kotlin/util/mc/NbtItemData.kt4
-rw-r--r--src/main/kotlin/util/skyblock/Rarity.kt17
-rw-r--r--src/main/kotlin/util/skyblock/SkyBlockItems.kt1
-rw-r--r--src/main/kotlin/util/textutil.kt6
14 files changed, 273 insertions, 48 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/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<Widget> {
val list = mutableListOf<Widget>()
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 {
diff --git a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt
index d2c555b..fdc378a 100644
--- a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt
+++ b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt
@@ -29,18 +29,7 @@ object ItemRarityCosmetics : FirmamentFeature {
override val config: ManagedConfig
get() = TConfig
- private val rarityToColor = 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,
- ).mapValues {
+ private val rarityToColor = Rarity.colourMap.mapValues {
val c = Color(it.value.colorValue!!)
c.rgb
}
diff --git a/src/main/kotlin/gui/entity/EntityRenderer.kt b/src/main/kotlin/gui/entity/EntityRenderer.kt
index 022b9a3..9a09fc6 100644
--- a/src/main/kotlin/gui/entity/EntityRenderer.kt
+++ b/src/main/kotlin/gui/entity/EntityRenderer.kt
@@ -111,8 +111,9 @@ object EntityRenderer {
renderContext: DrawContext,
posX: Int,
posY: Int,
- mouseX: Float,
- mouseY: Float
+ // TODO: Add width, height properties here
+ mouseX: Double,
+ mouseY: Double
) {
var bottomOffset = 0.0F
var currentEntity = entity
@@ -148,15 +149,15 @@ object EntityRenderer {
y2: Int,
size: Float,
bottomOffset: Float,
- mouseX: Float,
- mouseY: Float,
+ mouseX: Double,
+ mouseY: Double,
entity: LivingEntity
) {
context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
val centerX = (x1 + x2) / 2f
val centerY = (y1 + y2) / 2f
- val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat()
- val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat()
+ val targetYaw = atan(((centerX - mouseX) / 40.0f)).toFloat()
+ val targetPitch = atan(((centerY - mouseY) / 40.0f)).toFloat()
val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
rotateToFaceTheFront.mul(rotateToFaceTheCamera)
diff --git a/src/main/kotlin/repo/ItemCache.kt b/src/main/kotlin/repo/ItemCache.kt
index f88dd48..9f1d45c 100644
--- a/src/main/kotlin/repo/ItemCache.kt
+++ b/src/main/kotlin/repo/ItemCache.kt
@@ -39,6 +39,7 @@ import moe.nea.firmament.util.TestUtil
import moe.nea.firmament.util.directLiteralStringContent
import moe.nea.firmament.util.mc.FirmamentDataComponentTypes
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.modifyLore
import moe.nea.firmament.util.mc.setCustomName
@@ -131,6 +132,7 @@ object ItemCache : IReloadable {
val itemInstance =
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
itemInstance.loreAccordingToNbt = lore.map { un189Lore(it) }
+ itemInstance.displayNameAccordingToNbt = un189Lore(displayName)
val extraAttributes = oldItemTag.getCompound("tag").getCompound("ExtraAttributes")
if (extraAttributes != null)
itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes))
diff --git a/src/main/kotlin/repo/Reforge.kt b/src/main/kotlin/repo/Reforge.kt
index ea01818..b52adc6 100644
--- a/src/main/kotlin/repo/Reforge.kt
+++ b/src/main/kotlin/repo/Reforge.kt
@@ -108,6 +108,8 @@ data class Reforge(
@Serializable(with = RarityMapped.Serializer::class)
sealed interface RarityMapped<T> {
+ fun get(rarity: Rarity): T?
+
class Serializer<T>(
val values: KSerializer<T>
) : KSerializer<RarityMapped<T>> {
@@ -137,10 +139,18 @@ data class Reforge(
}
@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
- 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]
+ }
+ }
}
}
diff --git a/src/main/kotlin/repo/SBItemStack.kt b/src/main/kotlin/repo/SBItemStack.kt
index e5cacaa..a5f54ae 100644
--- a/src/main/kotlin/repo/SBItemStack.kt
+++ b/src/main/kotlin/repo/SBItemStack.kt
@@ -9,22 +9,31 @@ import net.minecraft.item.ItemStack
import net.minecraft.network.RegistryByteBuf
import net.minecraft.network.codec.PacketCodec
import net.minecraft.network.codec.PacketCodecs
+import net.minecraft.text.Style
import net.minecraft.text.Text
+import net.minecraft.text.TextColor
import net.minecraft.util.Formatting
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.LegacyFormattingCode
import moe.nea.firmament.util.ReforgeId
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.getUpgradeStars
+import moe.nea.firmament.util.grey
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.petData
+import moe.nea.firmament.util.prepend
import moe.nea.firmament.util.skyBlockId
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.useMatch
import moe.nea.firmament.util.withColor
data class SBItemStack constructor(
@@ -84,6 +93,117 @@ data class SBItemStack constructor(
}
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(
@@ -134,11 +254,19 @@ data class SBItemStack constructor(
}
- private fun appendReforgeStatsToLore(
+ private fun appendReforgeInfo(
itemStack: ItemStack,
) {
- val rarity = itemStack.rarity
- val lore = itemStack.loreAccordingToNbt
+ val rarity = Rarity.fromItem(itemStack) ?: return
+ 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
@@ -156,8 +284,8 @@ data class SBItemStack constructor(
injectReplacementDataForPets(replacementData)
return@run neuItem.asItemStack(idHint = skyblockId, replacementData)
.copyWithCount(stackSize)
+ .also { appendReforgeInfo(it) }
.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) }
}
if (itemStack_ == null)
diff --git a/src/main/kotlin/util/AprilFoolsUtil.kt b/src/main/kotlin/util/AprilFoolsUtil.kt
new file mode 100644
index 0000000..a940fa1
--- /dev/null
+++ b/src/main/kotlin/util/AprilFoolsUtil.kt
@@ -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
+ }
+}
diff --git a/src/main/kotlin/util/FirmFormatters.kt b/src/main/kotlin/util/FirmFormatters.kt
index 92fb9e5..4b32c2a 100644
--- a/src/main/kotlin/util/FirmFormatters.kt
+++ b/src/main/kotlin/util/FirmFormatters.kt
@@ -15,21 +15,25 @@ import net.minecraft.text.Text
object FirmFormatters {
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
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(double: Double, fractionalDigits: Int): String {
+ fun formatCommas(double: Double, fractionalDigits: Int, includeSign: Boolean = false): String {
val long = double.toLong()
val δ = (double - long).absoluteValue
val μ = pow(10, fractionalDigits)
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 {
diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt
index 497a2d2..631b444 100644
--- a/src/main/kotlin/util/SkyblockId.kt
+++ b/src/main/kotlin/util/SkyblockId.kt
@@ -106,7 +106,10 @@ data class HypixelPetInfo(
private val jsonparser = Json { ignoreUnknownKeys = true }
-val ItemStack.extraAttributes: NbtCompound
+var ItemStack.extraAttributes: NbtCompound
+ set(value) {
+ set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(value))
+ }
get() {
val customData = get(DataComponentTypes.CUSTOM_DATA) ?: run {
val component = NbtComponent.of(NbtCompound())
diff --git a/src/main/kotlin/util/mc/NbtItemData.kt b/src/main/kotlin/util/mc/NbtItemData.kt
index e8a908f..0c49862 100644
--- a/src/main/kotlin/util/mc/NbtItemData.kt
+++ b/src/main/kotlin/util/mc/NbtItemData.kt
@@ -5,8 +5,8 @@ import net.minecraft.component.type.LoreComponent
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
-var ItemStack.loreAccordingToNbt
- get() = get(DataComponentTypes.LORE)?.lines ?: listOf()
+var ItemStack.loreAccordingToNbt: List<Text>
+ get() = get(DataComponentTypes.LORE)?.lines ?: listOf()
set(value) {
set(DataComponentTypes.LORE, LoreComponent(value))
}
diff --git a/src/main/kotlin/util/skyblock/Rarity.kt b/src/main/kotlin/util/skyblock/Rarity.kt
index 0244630..b19f371 100644
--- a/src/main/kotlin/util/skyblock/Rarity.kt
+++ b/src/main/kotlin/util/skyblock/Rarity.kt
@@ -8,7 +8,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import net.minecraft.item.ItemStack
+import net.minecraft.text.Style
import net.minecraft.text.Text
+import net.minecraft.util.Formatting
import moe.nea.firmament.util.StringUtil.words
import moe.nea.firmament.util.collections.lastNotNullOfOrNull
import moe.nea.firmament.util.mc.loreAccordingToNbt
@@ -46,10 +48,23 @@ enum class Rarity(vararg altNames: String) {
}
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 }
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 fromNeuRepo = entries.associateBy { it.neuRepoRarity }
diff --git a/src/main/kotlin/util/skyblock/SkyBlockItems.kt b/src/main/kotlin/util/skyblock/SkyBlockItems.kt
index c94ebfe..cfd8429 100644
--- a/src/main/kotlin/util/skyblock/SkyBlockItems.kt
+++ b/src/main/kotlin/util/skyblock/SkyBlockItems.kt
@@ -7,4 +7,5 @@ object SkyBlockItems {
val ENCHANTED_DIAMOND = SkyblockId("ENCHANTED_DIAMOND")
val DIAMOND = SkyblockId("DIAMOND")
val ANCESTRAL_SPADE = SkyblockId("ANCESTRAL_SPADE")
+ val REFORGE_ANVIL = SkyblockId("REFORGE_ANVIL")
}
diff --git a/src/main/kotlin/util/textutil.kt b/src/main/kotlin/util/textutil.kt
index 06ed8c8..ab3de43 100644
--- a/src/main/kotlin/util/textutil.kt
+++ b/src/main/kotlin/util/textutil.kt
@@ -133,6 +133,7 @@ fun MutableText.darkGreen() = withColor(Formatting.DARK_GREEN)
fun MutableText.purple() = withColor(Formatting.DARK_PURPLE)
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.red() = withColor(Formatting.RED)
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 {
val c = this.content
if (c is TranslatableTextContent) {