diff options
Diffstat (limited to 'src/main/kotlin')
-rw-r--r-- | src/main/kotlin/features/FeatureManager.kt | 2 | ||||
-rw-r--r-- | src/main/kotlin/features/inventory/PetFeatures.kt | 40 | ||||
-rw-r--r-- | src/main/kotlin/util/MC.kt | 1 | ||||
-rw-r--r-- | src/main/kotlin/util/SkyblockId.kt | 198 |
4 files changed, 144 insertions, 97 deletions
diff --git a/src/main/kotlin/features/FeatureManager.kt b/src/main/kotlin/features/FeatureManager.kt index c2889eb..55f6328 100644 --- a/src/main/kotlin/features/FeatureManager.kt +++ b/src/main/kotlin/features/FeatureManager.kt @@ -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) diff --git a/src/main/kotlin/features/inventory/PetFeatures.kt b/src/main/kotlin/features/inventory/PetFeatures.kt new file mode 100644 index 0000000..81124f3 --- /dev/null +++ b/src/main/kotlin/features/inventory/PetFeatures.kt @@ -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")) + ) + } + } + + +} diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt index 09aa7aa..fc42be9 100644 --- a/src/main/kotlin/util/MC.kt +++ b/src/main/kotlin/util/MC.kt @@ -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 diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt index 59b1d2c..5b96dfa 100644 --- a/src/main/kotlin/util/SkyblockId.kt +++ b/src/main/kotlin/util/SkyblockId.kt @@ -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') } - }) - - 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(":", "-")) - } - } - - 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 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 + } + + /** + * 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() + } } 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 - } - - "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)}") - } - - "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)}") - } - - // TODO: PARTY_HAT_CRAB{,_ANIMATED,_SLOTH},POTION - else -> { - SkyblockId(id) - } - } - } + get() { + return when (val id = extraAttributes.getString("id")) { + "" -> { + 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)}") + } + + "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)}") + } + + // TODO: PARTY_HAT_CRAB{,_ANIMATED,_SLOTH},POTION + else -> { + SkyblockId(id) + } + } + } |