Add current pet highlighter
This commit is contained in:
@@ -21,6 +21,7 @@ import moe.nea.firmament.features.fixes.CompatibliltyFeatures
|
||||
import moe.nea.firmament.features.fixes.Fixes
|
||||
import moe.nea.firmament.features.inventory.CraftingOverlay
|
||||
import moe.nea.firmament.features.inventory.ItemRarityCosmetics
|
||||
import moe.nea.firmament.features.inventory.PetFeatures
|
||||
import moe.nea.firmament.features.inventory.PriceData
|
||||
import moe.nea.firmament.features.inventory.SaveCursorPosition
|
||||
import moe.nea.firmament.features.inventory.SlotLocking
|
||||
@@ -67,6 +68,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
||||
loadFeature(CompatibliltyFeatures)
|
||||
loadFeature(AnniversaryFeatures)
|
||||
loadFeature(QuickCommands)
|
||||
loadFeature(PetFeatures)
|
||||
loadFeature(SaveCursorPosition)
|
||||
loadFeature(CustomSkyBlockTextures)
|
||||
loadFeature(PriceData)
|
||||
|
||||
40
src/main/kotlin/features/inventory/PetFeatures.kt
Normal file
40
src/main/kotlin/features/inventory/PetFeatures.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package moe.nea.firmament.features.inventory
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.SlotRenderEvents
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.petData
|
||||
import moe.nea.firmament.util.unformattedString
|
||||
import moe.nea.firmament.util.useMatch
|
||||
|
||||
object PetFeatures : FirmamentFeature {
|
||||
override val identifier: String
|
||||
get() = "pets"
|
||||
|
||||
override val config: ManagedConfig?
|
||||
get() = TConfig
|
||||
|
||||
object TConfig : ManagedConfig(identifier) {
|
||||
val highlightEquippedPet by toggle("highlight-pet") { true }
|
||||
}
|
||||
|
||||
val petMenuTitle = "Pets(?: \\([0-9]+/[0-9]+\\))?".toPattern()
|
||||
|
||||
@Subscribe
|
||||
fun onSlotRender(event: SlotRenderEvents.Before) {
|
||||
if (!TConfig.highlightEquippedPet) return
|
||||
val stack = event.slot.stack
|
||||
if (stack.petData?.active == true)
|
||||
petMenuTitle.useMatch(MC.screenName ?: return) {
|
||||
event.context.drawSprite(
|
||||
event.slot.x, event.slot.y, 0, 16, 16,
|
||||
MC.guiAtlasManager.getSprite(Identifier.of("firmament:selected_pet_background"))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -86,6 +86,7 @@ object MC {
|
||||
inline var screen
|
||||
get() = instance.currentScreen
|
||||
set(value) = instance.setScreen(value)
|
||||
val screenName get() = screen?.title?.unformattedString?.trim()
|
||||
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
|
||||
inline val window get() = instance.window
|
||||
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
|
||||
|
||||
@file:UseSerializers(DashlessUUIDSerializer::class)
|
||||
|
||||
package moe.nea.firmament.util
|
||||
|
||||
import io.github.moulberry.repo.data.NEUItem
|
||||
import io.github.moulberry.repo.data.Rarity
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import net.minecraft.component.DataComponentTypes
|
||||
import net.minecraft.component.type.NbtComponent
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.repo.set
|
||||
import moe.nea.firmament.util.collections.WeakCache
|
||||
import moe.nea.firmament.util.json.DashlessUUIDSerializer
|
||||
|
||||
/**
|
||||
@@ -27,123 +28,126 @@ import moe.nea.firmament.util.json.DashlessUUIDSerializer
|
||||
@JvmInline
|
||||
@Serializable
|
||||
value class SkyblockId(val neuItem: String) {
|
||||
val identifier
|
||||
get() = Identifier.of("skyblockitem",
|
||||
neuItem.lowercase().replace(";", "__")
|
||||
.replace(":", "___")
|
||||
.replace(illlegalPathRegex) {
|
||||
it.value.toCharArray()
|
||||
.joinToString("") { "__" + it.code.toString(16).padStart(4, '0') }
|
||||
})
|
||||
val identifier
|
||||
get() = Identifier.of("skyblockitem",
|
||||
neuItem.lowercase().replace(";", "__")
|
||||
.replace(":", "___")
|
||||
.replace(illlegalPathRegex) {
|
||||
it.value.toCharArray()
|
||||
.joinToString("") { "__" + it.code.toString(16).padStart(4, '0') }
|
||||
})
|
||||
|
||||
override fun toString(): String {
|
||||
return neuItem
|
||||
}
|
||||
override fun toString(): String {
|
||||
return neuItem
|
||||
}
|
||||
|
||||
/**
|
||||
* A bazaar stock item id, as returned by the HyPixel bazaar api endpoint.
|
||||
* These are not equivalent to the in-game ids, or the NEU repo ids, and in fact, do not refer to items, but instead
|
||||
* to bazaar stocks. The main difference from [SkyblockId]s is concerning enchanted books. There are probably more,
|
||||
* but for now this holds.
|
||||
*/
|
||||
@JvmInline
|
||||
@Serializable
|
||||
value class BazaarStock(val bazaarId: String) {
|
||||
fun toRepoId(): SkyblockId {
|
||||
bazaarEnchantmentRegex.matchEntire(bazaarId)?.let {
|
||||
return SkyblockId("${it.groupValues[1]};${it.groupValues[2]}")
|
||||
}
|
||||
return SkyblockId(bazaarId.replace(":", "-"))
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A bazaar stock item id, as returned by the HyPixel bazaar api endpoint.
|
||||
* These are not equivalent to the in-game ids, or the NEU repo ids, and in fact, do not refer to items, but instead
|
||||
* to bazaar stocks. The main difference from [SkyblockId]s is concerning enchanted books. There are probably more,
|
||||
* but for now this holds.
|
||||
*/
|
||||
@JvmInline
|
||||
@Serializable
|
||||
value class BazaarStock(val bazaarId: String) {
|
||||
fun toRepoId(): SkyblockId {
|
||||
bazaarEnchantmentRegex.matchEntire(bazaarId)?.let {
|
||||
return SkyblockId("${it.groupValues[1]};${it.groupValues[2]}")
|
||||
}
|
||||
return SkyblockId(bazaarId.replace(":", "-"))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val COINS: SkyblockId = SkyblockId("SKYBLOCK_COIN")
|
||||
private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex()
|
||||
val NULL: SkyblockId = SkyblockId("null")
|
||||
val PET_NULL: SkyblockId = SkyblockId("null_pet")
|
||||
private val illlegalPathRegex = "[^a-z0-9_.-/]".toRegex()
|
||||
}
|
||||
companion object {
|
||||
val COINS: SkyblockId = SkyblockId("SKYBLOCK_COIN")
|
||||
private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex()
|
||||
val NULL: SkyblockId = SkyblockId("null")
|
||||
val PET_NULL: SkyblockId = SkyblockId("null_pet")
|
||||
private val illlegalPathRegex = "[^a-z0-9_.-/]".toRegex()
|
||||
}
|
||||
}
|
||||
|
||||
val NEUItem.skyblockId get() = SkyblockId(skyblockItemId)
|
||||
|
||||
@Serializable
|
||||
data class HypixelPetInfo(
|
||||
val type: String,
|
||||
val tier: Rarity,
|
||||
val exp: Double = 0.0,
|
||||
val candyUsed: Int = 0,
|
||||
val uuid: UUID? = null,
|
||||
val type: String,
|
||||
val tier: Rarity,
|
||||
val exp: Double = 0.0,
|
||||
val candyUsed: Int = 0,
|
||||
val uuid: UUID? = null,
|
||||
val active: Boolean = false,
|
||||
) {
|
||||
val skyblockId get() = SkyblockId("${type.uppercase()};${tier.ordinal}")
|
||||
val skyblockId get() = SkyblockId("${type.uppercase()};${tier.ordinal}")
|
||||
}
|
||||
|
||||
private val jsonparser = Json { ignoreUnknownKeys = true }
|
||||
|
||||
val ItemStack.extraAttributes: NbtCompound
|
||||
get() {
|
||||
val customData = get(DataComponentTypes.CUSTOM_DATA) ?: run {
|
||||
val component = NbtComponent.of(NbtCompound())
|
||||
set(DataComponentTypes.CUSTOM_DATA, component)
|
||||
component
|
||||
}
|
||||
return customData.nbt
|
||||
}
|
||||
get() {
|
||||
val customData = get(DataComponentTypes.CUSTOM_DATA) ?: run {
|
||||
val component = NbtComponent.of(NbtCompound())
|
||||
set(DataComponentTypes.CUSTOM_DATA, component)
|
||||
component
|
||||
}
|
||||
return customData.nbt
|
||||
}
|
||||
|
||||
val ItemStack.skyblockUUIDString: String?
|
||||
get() = extraAttributes.getString("uuid")?.takeIf { it.isNotBlank() }
|
||||
get() = extraAttributes.getString("uuid")?.takeIf { it.isNotBlank() }
|
||||
|
||||
val ItemStack.skyblockUUID: UUID?
|
||||
get() = skyblockUUIDString?.let { UUID.fromString(it) }
|
||||
get() = skyblockUUIDString?.let { UUID.fromString(it) }
|
||||
|
||||
private val petDataCache = WeakCache.memoize<ItemStack, Optional<HypixelPetInfo>>("PetInfo") {
|
||||
val jsonString = it.extraAttributes.getString("petInfo")
|
||||
if (jsonString.isNullOrBlank()) return@memoize Optional.empty()
|
||||
runCatching { jsonparser.decodeFromString<HypixelPetInfo>(jsonString) }
|
||||
.getOrElse { null }.intoOptional()
|
||||
}
|
||||
|
||||
val ItemStack.petData: HypixelPetInfo?
|
||||
get() {
|
||||
val jsonString = extraAttributes.getString("petInfo")
|
||||
if (jsonString.isNullOrBlank()) return null
|
||||
return runCatching { jsonparser.decodeFromString<HypixelPetInfo>(jsonString) }
|
||||
.getOrElse { return null }
|
||||
}
|
||||
get() = petDataCache(this).getOrNull()
|
||||
|
||||
fun ItemStack.setSkyBlockFirmamentUiId(uiId: String) = setSkyBlockId(SkyblockId("FIRMAMENT_UI_$uiId"))
|
||||
fun ItemStack.setSkyBlockId(skyblockId: SkyblockId): ItemStack {
|
||||
this.extraAttributes["id"] = skyblockId.neuItem
|
||||
return this
|
||||
this.extraAttributes["id"] = skyblockId.neuItem
|
||||
return this
|
||||
}
|
||||
|
||||
val ItemStack.skyBlockId: SkyblockId?
|
||||
get() {
|
||||
return when (val id = extraAttributes.getString("id")) {
|
||||
"" -> {
|
||||
null
|
||||
}
|
||||
get() {
|
||||
return when (val id = extraAttributes.getString("id")) {
|
||||
"" -> {
|
||||
null
|
||||
}
|
||||
|
||||
"PET" -> {
|
||||
petData?.skyblockId ?: SkyblockId.PET_NULL
|
||||
}
|
||||
"PET" -> {
|
||||
petData?.skyblockId ?: SkyblockId.PET_NULL
|
||||
}
|
||||
|
||||
"RUNE", "UNIQUE_RUNE" -> {
|
||||
val runeData = extraAttributes.getCompound("runes")
|
||||
val runeKind = runeData.keys.singleOrNull()
|
||||
if (runeKind == null) SkyblockId("RUNE")
|
||||
else SkyblockId("${runeKind.uppercase()}_RUNE;${runeData.getInt(runeKind)}")
|
||||
}
|
||||
"RUNE", "UNIQUE_RUNE" -> {
|
||||
val runeData = extraAttributes.getCompound("runes")
|
||||
val runeKind = runeData.keys.singleOrNull()
|
||||
if (runeKind == null) SkyblockId("RUNE")
|
||||
else SkyblockId("${runeKind.uppercase()}_RUNE;${runeData.getInt(runeKind)}")
|
||||
}
|
||||
|
||||
"ABICASE" -> {
|
||||
SkyblockId("ABICASE_${extraAttributes.getString("model").uppercase()}")
|
||||
}
|
||||
"ABICASE" -> {
|
||||
SkyblockId("ABICASE_${extraAttributes.getString("model").uppercase()}")
|
||||
}
|
||||
|
||||
"ENCHANTED_BOOK" -> {
|
||||
val enchantmentData = extraAttributes.getCompound("enchantments")
|
||||
val enchantName = enchantmentData.keys.singleOrNull()
|
||||
if (enchantName == null) SkyblockId("ENCHANTED_BOOK")
|
||||
else SkyblockId("${enchantName.uppercase()};${enchantmentData.getInt(enchantName)}")
|
||||
}
|
||||
"ENCHANTED_BOOK" -> {
|
||||
val enchantmentData = extraAttributes.getCompound("enchantments")
|
||||
val enchantName = enchantmentData.keys.singleOrNull()
|
||||
if (enchantName == null) SkyblockId("ENCHANTED_BOOK")
|
||||
else SkyblockId("${enchantName.uppercase()};${enchantmentData.getInt(enchantName)}")
|
||||
}
|
||||
|
||||
// TODO: PARTY_HAT_CRAB{,_ANIMATED,_SLOTH},POTION
|
||||
else -> {
|
||||
SkyblockId(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: PARTY_HAT_CRAB{,_ANIMATED,_SLOTH},POTION
|
||||
else -> {
|
||||
SkyblockId(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
"firmament.config.repo.disable-item-groups": "Disable Item Groups",
|
||||
"firmament.config.repo.reload": "Reload Item List",
|
||||
"firmament.config.repo.redownload": "Redownload Item List",
|
||||
"firmament.config.pets": "Pets",
|
||||
"firmament.config.pets.highlight-pet": "Highlight active pet",
|
||||
"firmament.ursa.debugrequest.start": "Ursa request launched",
|
||||
"firmament.ursa.debugrequest.result": "Ursa request succeeded: %s",
|
||||
"firmament.sbinfo.nolocraw": "No locraw data available",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 558 B |
Reference in New Issue
Block a user