feat: Add Pet overlay

* feat: pet overlay

* fix: missing shadow

* fix: getting pet when not in pets menu

* sort translations

* Merge branch 'master' into feat/pet-overlay

* Merge branch 'master' into feat/pet-overlay

* Add requested changes for Pet Overlay
This commit is contained in:
Jacob
2025-05-08 05:20:29 +08:00
committed by GitHub
parent 63669bc28b
commit 40256ca601
7 changed files with 75 additions and 8 deletions

View File

@@ -50,7 +50,7 @@ object Fixes : FirmamentFeature {
"firmament.fixes.auto-sprint.sprinting" "firmament.fixes.auto-sprint.sprinting"
else else
"firmament.fixes.auto-sprint.not-sprinting" "firmament.fixes.auto-sprint.not-sprinting"
), 0, 0, -1, false ), 0, 0, -1, true
) )
it.context.matrices.pop() it.context.matrices.pop()
} }

View File

@@ -1,14 +1,24 @@
package moe.nea.firmament.features.inventory package moe.nea.firmament.features.inventory
import net.minecraft.util.Identifier import moe.nea.jarvis.api.Point
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import net.minecraft.util.Formatting
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.FirmFormatters.formatPercent
import moe.nea.firmament.util.FirmFormatters.shortFormat
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.petData import moe.nea.firmament.util.petData
import moe.nea.firmament.util.render.drawGuiTexture import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.skyblock.Rarity
import moe.nea.firmament.util.titleCase
import moe.nea.firmament.util.useMatch import moe.nea.firmament.util.useMatch
import moe.nea.firmament.util.withColor
object PetFeatures : FirmamentFeature { object PetFeatures : FirmamentFeature {
override val identifier: String override val identifier: String
@@ -19,9 +29,12 @@ object PetFeatures : FirmamentFeature {
object TConfig : ManagedConfig(identifier, Category.INVENTORY) { object TConfig : ManagedConfig(identifier, Category.INVENTORY) {
val highlightEquippedPet by toggle("highlight-pet") { true } val highlightEquippedPet by toggle("highlight-pet") { true }
var petOverlay by toggle("pet-overlay") { false }
val petOverlayHud by position("pet-overlay-hud", 80, 10) { Point(0.5, 1.0) }
} }
val petMenuTitle = "Pets(?: \\([0-9]+/[0-9]+\\))?".toPattern() val petMenuTitle = "Pets(?: \\([0-9]+/[0-9]+\\))?".toPattern()
var petItemStack: ItemStack? = null
@Subscribe @Subscribe
fun onSlotRender(event: SlotRenderEvents.Before) { fun onSlotRender(event: SlotRenderEvents.Before) {
@@ -29,12 +42,44 @@ object PetFeatures : FirmamentFeature {
val stack = event.slot.stack val stack = event.slot.stack
if (stack.petData?.active == true) if (stack.petData?.active == true)
petMenuTitle.useMatch(MC.screenName ?: return) { petMenuTitle.useMatch(MC.screenName ?: return) {
event.context.drawGuiTexture( petItemStack = stack
event.slot.x, event.slot.y, 0, 16, 16, event.context.drawGuiTexture(
Identifier.of("firmament:selected_pet_background") Firmament.identifier("selected_pet_background"),
) event.slot.x, event.slot.y, 16, 16,
} )
}
} }
@Subscribe
fun onRenderHud(it: HudRenderEvent) {
if (!TConfig.petOverlay) return
val itemStack = petItemStack ?: return
val petData = petItemStack?.petData ?: return
val rarity = Rarity.fromNeuRepo(petData.tier)
val rarityCode = Rarity.colourMap[rarity] ?: Formatting.WHITE
val xp = petData.level
val petType = titleCase(petData.type)
val heldItem = petData.heldItem?.let { item -> "Held Item: ${titleCase(item)}" }
it.context.matrices.push()
TConfig.petOverlayHud.applyTransformations(it.context.matrices)
val lines = mutableListOf<Text>()
it.context.matrices.push()
it.context.matrices.translate(-0.5, -0.5, 0.0)
it.context.matrices.scale(2f, 2f, 1f)
it.context.drawItem(itemStack, 0, 0)
it.context.matrices.pop()
lines.add(Text.literal("[Lvl ${xp.currentLevel}] ").append(Text.literal(petType).withColor(rarityCode)))
if (heldItem != null) lines.add(Text.literal(heldItem))
if (xp.currentLevel != xp.maxLevel) lines.add(Text.literal("Required L${xp.currentLevel + 1}: ${shortFormat(xp.expInCurrentLevel.toDouble())}/${shortFormat(xp.expRequiredForNextLevel.toDouble())} (${formatPercent(xp.percentageToNextLevel.toDouble())})"))
lines.add(Text.literal("Required L100: ${shortFormat(xp.expTotal.toDouble())}/${shortFormat(xp.expRequiredForMaxLevel.toDouble())} (${formatPercent(xp.percentageToMaxLevel.toDouble())})"))
for ((index, line) in lines.withIndex()) {
it.context.drawText(MC.font, line.copy().withColor(Formatting.GRAY), 36, MC.font.fontHeight * index, -1, true)
}
it.context.matrices.pop()
}
} }

View File

@@ -19,7 +19,8 @@ object ExpLadders : IReloadable {
val expInCurrentLevel: Float, val expInCurrentLevel: Float,
var expTotal: Float, var expTotal: Float,
) { ) {
val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel
val percentageToMaxLevel: Float = expTotal / expRequiredForMaxLevel
} }
data class ExpLadder( data class ExpLadder(

View File

@@ -135,4 +135,8 @@ object FirmFormatters {
fun formatPosition(position: BlockPos): Text { fun formatPosition(position: BlockPos): Text {
return Text.literal("x: ${position.x}, y: ${position.y}, z: ${position.z}") return Text.literal("x: ${position.x}, y: ${position.y}, z: ${position.z}")
} }
fun formatPercent(value: Double, decimals: Int = 1): String {
return "%.${decimals}f%%".format(value * 100)
}
} }

View File

@@ -21,6 +21,7 @@ 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.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.repo.ExpLadders
import moe.nea.firmament.repo.ItemCache.asItemStack import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.set import moe.nea.firmament.repo.set
import moe.nea.firmament.util.collections.WeakCache import moe.nea.firmament.util.collections.WeakCache
@@ -104,8 +105,10 @@ data class HypixelPetInfo(
val candyUsed: Int = 0, val candyUsed: Int = 0,
val uuid: UUID? = null, val uuid: UUID? = null,
val active: Boolean = false, val active: Boolean = false,
val heldItem: String? = null,
) { ) {
val skyblockId get() = SkyblockId("${type.uppercase()};${tier.ordinal}") // TODO: is this ordinal set up correctly? val skyblockId get() = SkyblockId("${type.uppercase()};${tier.ordinal}") // TODO: is this ordinal set up correctly?
val level get() = ExpLadders.getExpLadder(type, tier).getPetLevel(exp)
} }
private val jsonparser = Json { ignoreUnknownKeys = true } private val jsonparser = Json { ignoreUnknownKeys = true }

View File

@@ -164,4 +164,14 @@ fun Text.transformEachRecursively(function: (Text) -> Text): Text {
fun tr(key: String, default: String): MutableText = error("Compiler plugin did not run.") fun tr(key: String, default: String): MutableText = error("Compiler plugin did not run.")
fun trResolved(key: String, vararg args: Any): MutableText = Text.stringifiedTranslatable(key, *args) fun trResolved(key: String, vararg args: Any): MutableText = Text.stringifiedTranslatable(key, *args)
fun titleCase(str: String): String {
return str
.lowercase()
.replace("_", " ")
.split(" ")
.joinToString(" ") { word ->
word.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
}
}

View File

@@ -161,6 +161,10 @@
"firmament.config.pets": "Pets", "firmament.config.pets": "Pets",
"firmament.config.pets.highlight-pet": "Highlight active pet", "firmament.config.pets.highlight-pet": "Highlight active pet",
"firmament.config.pets.highlight-pet.description": "Highlight your currently selected pet in the /pets menu.", "firmament.config.pets.highlight-pet.description": "Highlight your currently selected pet in the /pets menu.",
"firmament.config.pets.pet-overlay": "Pet Info",
"firmament.config.pets.pet-overlay-hud": "Pet Info Hud",
"firmament.config.pets.pet-overlay-hud.description": "A HUD showing current active pet and the pet exp.",
"firmament.config.pets.pet-overlay.description": "Shows current active pet and pet exp on screen.",
"firmament.config.pickaxe-info": "Pickaxes & Drills", "firmament.config.pickaxe-info": "Pickaxes & Drills",
"firmament.config.pickaxe-info.ability-cooldown": "Pickaxe Ability Cooldown", "firmament.config.pickaxe-info.ability-cooldown": "Pickaxe Ability Cooldown",
"firmament.config.pickaxe-info.ability-cooldown-toast": "Pickaxe Ability Ready Toast", "firmament.config.pickaxe-info.ability-cooldown-toast": "Pickaxe Ability Ready Toast",