aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gradle/libs.versions.toml2
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/profileviewer/PetsPage.kt5
-rw-r--r--src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt5
-rw-r--r--src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt2
-rw-r--r--src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt52
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt92
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt35
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt20
8 files changed, 195 insertions, 18 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index d73e42c..3354484 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,7 +11,7 @@ modmenu = "6.2.1"
ktor = "2.3.0"
dbus_java = "4.2.1"
architectury = "8.1.79"
-neurepoparser = "1.2.0"
+neurepoparser = "1.3.1"
qolify = "1.2.2-1.19.4"
citresewn = "1.1.3+1.19.4"
lib39 = "1.4.2"
diff --git a/src/main/kotlin/moe/nea/firmament/gui/profileviewer/PetsPage.kt b/src/main/kotlin/moe/nea/firmament/gui/profileviewer/PetsPage.kt
index bf412b9..4c669df 100644
--- a/src/main/kotlin/moe/nea/firmament/gui/profileviewer/PetsPage.kt
+++ b/src/main/kotlin/moe/nea/firmament/gui/profileviewer/PetsPage.kt
@@ -6,7 +6,6 @@ import io.github.cottonmc.cotton.gui.widget.WGridPanel
import io.github.cottonmc.cotton.gui.widget.WItem
import io.github.cottonmc.cotton.gui.widget.WText
import io.github.cottonmc.cotton.gui.widget.WWidget
-import io.github.cottonmc.cotton.gui.widget.data.InputResult
import io.github.cottonmc.cotton.gui.widget.data.Insets
import io.github.cottonmc.cotton.gui.widget.icon.Icon
import io.github.cottonmc.cotton.gui.widget.icon.ItemIcon
@@ -15,8 +14,8 @@ import net.minecraft.client.util.math.MatrixStack
import net.minecraft.item.Items
import net.minecraft.text.Text
import moe.nea.firmament.gui.WTightScrollPanel
+import moe.nea.firmament.rei.PetData
import moe.nea.firmament.rei.SBItemStack
-import moe.nea.firmament.util.MC
object PetsPage : ProfilePage {
override fun getElements(profileViewer: ProfileViewer): WWidget {
@@ -26,7 +25,7 @@ object PetsPage : ProfilePage {
it.add((WTightScrollPanel(WGridPanel().also {
it.setGaps(8, 8)
for ((i, pet) in profileViewer.member.pets.withIndex()) {
- val stack = SBItemStack(pet.itemId, 1).asItemStack()
+ val stack = SBItemStack(pet.itemId, PetData(pet.tier, pet.type.name, pet.exp)).asItemStack()
it.add(object : WItem(stack) {
override fun paint(matrices: MatrixStack?, x: Int, y: Int, mouseX: Int, mouseY: Int) {
BackgroundPainter.SLOT.paintBackground(matrices, x, y, this)
diff --git a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt b/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt
index 87efaac..8b8383a 100644
--- a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt
+++ b/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt
@@ -35,6 +35,7 @@ import moe.nea.firmament.recipes.SBForgeRecipe
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.SkyblockId
+import moe.nea.firmament.util.skyblockId
class FirmamentReiPlugin : REIClientPlugin {
@@ -73,7 +74,7 @@ class FirmamentReiPlugin : REIClientPlugin {
registry.group(
SkyblockId(parent).identifier,
Text.literal(RepoManager.getNEUItem(SkyblockId(parent))?.displayName ?: parent),
- (children + parent).map { SBItemEntryDefinition.getEntry(RepoManager.getNEUItem(SkyblockId(it))) })
+ (children + parent).map { SBItemEntryDefinition.getEntry(SkyblockId(it)) })
}
}
@@ -84,7 +85,7 @@ class FirmamentReiPlugin : REIClientPlugin {
override fun registerEntries(registry: EntryRegistry) {
RepoManager.neuRepo.items?.items?.values?.forEach {
if (!it.isVanilla)
- registry.addEntry(SBItemEntryDefinition.getEntry(it))
+ registry.addEntry(SBItemEntryDefinition.getEntry(it.skyblockId))
}
}
}
diff --git a/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt b/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt
index bf59940..7d98558 100644
--- a/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt
+++ b/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt
@@ -34,7 +34,7 @@ object NEUItemEntrySerializer : EntrySerializer<SBItemStack> {
override fun read(tag: NbtCompound): SBItemStack {
val id = SkyblockId(tag.getString(SKYBLOCK_ID_ENTRY))
val count = if (tag.contains(SKYBLOCK_ITEM_COUNT)) tag.getInt(SKYBLOCK_ITEM_COUNT) else 1
- return SBItemStack(id, RepoManager.getNEUItem(id), count)
+ return SBItemStack(id, count)
}
override fun save(entry: EntryStack<SBItemStack>, value: SBItemStack): NbtCompound {
diff --git a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt b/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt
index c38f350..f5f3401 100644
--- a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt
+++ b/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt
@@ -20,6 +20,7 @@ package moe.nea.firmament.rei
import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEUItem
+import io.github.moulberry.repo.data.Rarity
import java.util.stream.Stream
import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer
import me.shedaniel.rei.api.common.entry.EntrySerializer
@@ -33,28 +34,64 @@ import net.minecraft.registry.tag.TagKey
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry
+import moe.nea.firmament.repo.ExpLadders
import moe.nea.firmament.repo.ItemCache
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.RepoManager
+import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.SkyblockId
-import moe.nea.firmament.util.skyblockId
// TODO: add in extra data like pet info, into this structure
+data class PetData(
+ val rarity: Rarity,
+ val petId: String,
+ val exp: Double,
+) {
+ val levelData by lazy { ExpLadders.getExpLadder(petId, rarity).getPetLevel(exp) }
+}
+
data class SBItemStack(
val skyblockId: SkyblockId,
val neuItem: NEUItem?,
val stackSize: Int,
+ val petData: PetData?,
) {
+ constructor(skyblockId: SkyblockId, petData: PetData) : this(
+ skyblockId,
+ RepoManager.getNEUItem(skyblockId),
+ 1,
+ petData
+ )
+
constructor(skyblockId: SkyblockId, stackSize: Int = 1) : this(
skyblockId,
RepoManager.getNEUItem(skyblockId),
- stackSize
+ stackSize,
+ RepoManager.getPotentialStubPetData(skyblockId)
)
- fun asItemStack(): ItemStack {
+ private val itemStack by lazy {
if (skyblockId == SkyblockId.COINS)
- return ItemCache.coinItem(stackSize)
- return neuItem.asItemStack(idHint = skyblockId).copyWithCount(stackSize)
+ return@lazy ItemCache.coinItem(stackSize)
+ val replacementData = mutableMapOf<String, String>()
+ if (petData != null) {
+ val stats = RepoManager.neuRepo.constants.petNumbers[petData.petId]?.get(petData.rarity)
+ ?.interpolatedStatsAtLevel(petData.levelData.currentLevel)
+ if (stats != null) {
+ stats.otherNumbers.forEachIndexed { index, it ->
+ replacementData[index.toString()] = FirmFormatters.toString(it, 0)
+ }
+ stats.statNumbers.forEach { (t, u) ->
+ replacementData[t] = FirmFormatters.toString(u, 0)
+ }
+ }
+ replacementData["LVL"] = petData.levelData.currentLevel.toString()
+ }
+ return@lazy neuItem.asItemStack(idHint = skyblockId, replacementData).copyWithCount(stackSize)
+ }
+
+ fun asItemStack(): ItemStack {
+ return itemStack.copy()
}
}
@@ -112,11 +149,8 @@ object SBItemEntryDefinition : EntryDefinition<SBItemStack> {
fun getEntry(sbItemStack: SBItemStack): EntryStack<SBItemStack> =
EntryStack.of(this, sbItemStack)
- fun getEntry(neuItem: NEUItem?, count: Int = 1): EntryStack<SBItemStack> =
- getEntry(SBItemStack(neuItem?.skyblockId ?: SkyblockId.NULL, neuItem, 1))
-
fun getEntry(skyblockId: SkyblockId, count: Int = 1): EntryStack<SBItemStack> =
- getEntry(SBItemStack(skyblockId, RepoManager.getNEUItem(skyblockId), count))
+ getEntry(SBItemStack(skyblockId, count))
fun getEntry(ingredient: NEUIngredient): EntryStack<SBItemStack> =
getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount.toInt())
diff --git a/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt b/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt
new file mode 100644
index 0000000..082483b
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt
@@ -0,0 +1,92 @@
+package moe.nea.firmament.repo
+
+import com.google.common.cache.CacheBuilder
+import com.google.common.cache.CacheLoader
+import io.github.moulberry.repo.IReloadable
+import io.github.moulberry.repo.NEURepository
+import io.github.moulberry.repo.constants.PetLevelingBehaviourOverride
+import io.github.moulberry.repo.data.Rarity
+
+object ExpLadders : IReloadable {
+
+ data class PetLevel(
+ val currentLevel: Int,
+ val maxLevel: Int,
+ val expRequiredForNextLevel: Long,
+ val expRequiredForMaxLevel: Long,
+ val expInCurrentLevel: Float,
+ var expTotal: Float,
+ ) {
+ val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel
+ }
+
+ data class ExpLadder(
+ val individualLevelCost: List<Long>,
+ ) {
+ val cumulativeLevelCost = individualLevelCost.runningFold(0F) { a, b -> a + b }.map { it.toLong() }
+ fun getPetLevel(currentExp: Double): PetLevel {
+ val currentOneIndexedLevel = cumulativeLevelCost.indexOfLast { it <= currentExp } + 1
+ val expForNextLevel = if (currentOneIndexedLevel > individualLevelCost.size) { // Max leveled pet
+ individualLevelCost.last()
+ } else {
+ individualLevelCost[currentOneIndexedLevel - 1]
+ }
+ val expInCurrentLevel =
+ if (currentOneIndexedLevel >= cumulativeLevelCost.size)
+ currentExp.toFloat() - cumulativeLevelCost.last()
+ else
+ (expForNextLevel - (cumulativeLevelCost[currentOneIndexedLevel] - currentExp.toFloat())).coerceAtLeast(
+ 0F
+ )
+ return PetLevel(
+ currentLevel = currentOneIndexedLevel,
+ maxLevel = cumulativeLevelCost.size,
+ expRequiredForNextLevel = expForNextLevel,
+ expRequiredForMaxLevel = cumulativeLevelCost.last(),
+ expInCurrentLevel = expInCurrentLevel,
+ expTotal = currentExp.toFloat()
+ )
+ }
+
+ fun getPetExpForLevel(level: Int): Long {
+ if (level < 2) return 0L
+ if (level >= cumulativeLevelCost.size) return cumulativeLevelCost.last()
+ return cumulativeLevelCost[level - 1]
+ }
+ }
+
+ private data class Key(val petIdWithoutRarity: String, val rarity: Rarity)
+
+ private val expLadders = CacheBuilder.newBuilder()
+ .build(object : CacheLoader<Key, ExpLadder>() {
+ override fun load(key: Key): ExpLadder {
+ val pld = RepoManager.neuRepo.constants.petLevelingData
+ var exp = pld.petExpCostForLevel
+ var offset = pld.petLevelStartOffset[key.rarity]!!
+ var maxLevel = 100
+ val override = pld.petLevelingBehaviourOverrides[key.petIdWithoutRarity]
+ if (override != null) {
+ maxLevel = override.maxLevel ?: maxLevel
+ offset = override.petLevelStartOffset?.get(key.rarity) ?: offset
+ when (override.petExpCostModifierType) {
+ PetLevelingBehaviourOverride.PetExpModifierType.APPEND ->
+ exp = exp + override.petExpCostModifier
+
+ PetLevelingBehaviourOverride.PetExpModifierType.REPLACE ->
+ exp = override.petExpCostModifier
+
+ null -> {}
+ }
+ }
+ return ExpLadder(exp.drop(offset).take(maxLevel - 1).map { it.toLong() })
+ }
+ })
+
+ override fun reload(repository: NEURepository?) {
+ expLadders.invalidateAll()
+ }
+
+ fun getExpLadder(petId: String, rarity: Rarity): ExpLadder {
+ return expLadders.get(Key(petId, rarity))
+ }
+}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt b/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt
index 5452d33..681dba5 100644
--- a/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt
+++ b/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt
@@ -41,12 +41,15 @@ import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtElement
import net.minecraft.nbt.NbtHelper
+import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtOps
+import net.minecraft.nbt.NbtString
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.util.LegacyTagParser
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.appendLore
+import moe.nea.firmament.util.getOrCreateList
import moe.nea.firmament.util.item.MinecraftProfileTextureKt
import moe.nea.firmament.util.item.MinecraftTexturesPayloadKt
import moe.nea.firmament.util.item.setTextures
@@ -103,16 +106,46 @@ object ItemCache : IReloadable {
}
}
- fun NEUItem?.asItemStack(idHint: SkyblockId? = null): ItemStack {
+ fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack {
if (this == null) return brokenItemStack(null, idHint)
var s = cache[this.skyblockItemId]
if (s == null) {
s = asItemStackNow()
cache[this.skyblockItemId] = s
}
+ if (!loreReplacements.isNullOrEmpty()) {
+ s.applyLoreReplacements(loreReplacements)
+ s.setCustomName(s.name.applyLoreReplacements(loreReplacements))
+ }
return s
}
+ fun ItemStack.applyLoreReplacements(loreReplacements: Map<String, String>) {
+ val component = getOrCreateSubNbt("display")
+ val lore = component.getOrCreateList("Lore", NbtString.STRING_TYPE)
+ val newLore = NbtList()
+ lore.forEach {
+ newLore.add(
+ NbtString.of(
+ Text.Serializer.toJson(
+ Text.Serializer.fromJson(it.asString())!!.applyLoreReplacements(loreReplacements)
+ )
+ )
+ )
+ }
+ component["Lore"] = newLore
+ }
+
+ fun Text.applyLoreReplacements(loreReplacements: Map<String, String>): Text {
+ assert(this.siblings.isEmpty())
+ var string = this.string
+ loreReplacements.forEach { (find, replace) ->
+ string = string.replace("{$find}", replace)
+ }
+ return Text.literal(string).styled { this.style }
+ }
+
+
fun NEUItem.getIdentifier() = skyblockId.identifier
diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt
index b431d28..1880617 100644
--- a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt
+++ b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt
@@ -24,6 +24,7 @@ import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.NEURepositoryException
import io.github.moulberry.repo.data.NEUItem
import io.github.moulberry.repo.data.NEURecipe
+import io.github.moulberry.repo.data.Rarity
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import kotlinx.coroutines.launch
import net.minecraft.client.MinecraftClient
@@ -31,9 +32,10 @@ import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.Firmament.logger
+import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.hud.ProgressBar
+import moe.nea.firmament.rei.PetData
import moe.nea.firmament.util.SkyblockId
-import moe.nea.firmament.gui.config.ManagedConfig
object RepoManager {
object Config : ManagedConfig("repo") {
@@ -59,6 +61,7 @@ object RepoManager {
val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply {
registerReloadListener(ItemCache)
+ registerReloadListener(ExpLadders)
registerReloadListener {
if (!trySendClientboundUpdateRecipesPacket()) {
logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
@@ -121,4 +124,19 @@ object RepoManager {
}
}
+ fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? {
+ val parts = skyblockId.neuItem.split(";")
+ if (parts.size != 2) {
+ return null
+ }
+ val (petId, rarityIndex) = parts
+ if (!rarityIndex.all { it.isDigit() }) {
+ return null
+ }
+ val intIndex = rarityIndex.toInt()
+ if (intIndex !in rarityIndex.indices) return null
+ if (petId !in neuRepo.constants.petNumbers) return null
+ return PetData(Rarity.values()[intIndex], petId, 0.0)
+ }
+
}