diff options
5 files changed, 245 insertions, 8 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt b/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt new file mode 100644 index 0000000..c9286fc --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt @@ -0,0 +1,108 @@ +@file:UseSerializers(DashlessUUIDSerializer::class, InstantAsLongSerializer::class) + +package moe.nea.firmament.apis + +import io.github.moulberry.repo.constants.Leveling +import io.github.moulberry.repo.data.Rarity +import java.util.UUID +import kotlinx.datetime.Instant +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import kotlin.reflect.KProperty1 +import moe.nea.firmament.util.json.DashlessUUIDSerializer +import moe.nea.firmament.util.json.InstantAsLongSerializer + + +@Serializable +data class Profiles( + val success: Boolean, + val profiles: List<Profile> +) + +@Serializable +data class Profile( + @SerialName("profile_id") + val profileId: UUID, + @SerialName("cute_name") + val cuteName: String, + val selected: Boolean = false, + val members: Map<UUID, Member>, +) + +enum class Skill(val accessor: KProperty1<Member, Double>) { + FARMING(Member::experienceSkillFarming), + FORAGING(Member::experienceSkillForaging), + MINING(Member::experienceSkillMining), + ALCHEMY(Member::experienceSkillAlchemy), + TAMING(Member::experienceSkillTaming), + FISHING(Member::experienceSkillFishing), + RUNECRAFTING(Member::experienceSkillRunecrafting), + CARPENTRY(Member::experienceSkillCarpentry), + COMBAT(Member::experienceSkillCombat), + SOCIAL(Member::experienceSkillSocial), + ENCHANTING(Member::experienceSkillEnchanting), + ; + + fun getMaximumLevel(leveling: Leveling) = leveling.maximumLevels[name.lowercase()] ?: TODO("Repo error") + + fun getLadder(leveling: Leveling): List<Int> { + if (this == SOCIAL) return leveling.socialExperienceRequiredPerLevel + if (this == RUNECRAFTING) return leveling.runecraftingExperienceRequiredPerLevel + return leveling.skillExperienceRequiredPerLevel + } +} + +@Serializable +data class Member( + val pets: List<Pet>, + @SerialName("coop_invitation") + val coopInvitation: CoopInvitation? = null, + @SerialName("experience_skill_farming") + val experienceSkillFarming: Double = 0.0, + @SerialName("experience_skill_alchemy") + val experienceSkillAlchemy: Double = 0.0, + @SerialName("experience_skill_combat") + val experienceSkillCombat: Double = 0.0, + @SerialName("experience_skill_taming") + val experienceSkillTaming: Double = 0.0, + @SerialName("experience_skill_social2") + val experienceSkillSocial: Double = 0.0, + @SerialName("experience_skill_enchanting") + val experienceSkillEnchanting: Double = 0.0, + @SerialName("experience_skill_fishing") + val experienceSkillFishing: Double = 0.0, + @SerialName("experience_skill_foraging") + val experienceSkillForaging: Double = 0.0, + @SerialName("experience_skill_mining") + val experienceSkillMining: Double = 0.0, + @SerialName("experience_skill_runecrafting") + val experienceSkillRunecrafting: Double = 0.0, + @SerialName("experience_skill_carpentry") + val experienceSkillCarpentry: Double = 0.0, +) + +@Serializable +data class CoopInvitation( + val timestamp: Instant, + @SerialName("invited_by") + val invitedBy: UUID? = null, + val confirmed: Boolean, +) + +@JvmInline +@Serializable +value class PetType(val name: String) + +@Serializable +data class Pet( + val uuid: UUID?, + val type: PetType, + val exp: Double, + val active: Boolean, + val tier: Rarity, + val candyUsed: Int, + val heldItem: String?, + val skin: String?, + + ) diff --git a/src/main/kotlin/moe/nea/firmament/commands/rome.kt b/src/main/kotlin/moe/nea/firmament/commands/rome.kt index 02b12d9..56ab84d 100644 --- a/src/main/kotlin/moe/nea/firmament/commands/rome.kt +++ b/src/main/kotlin/moe/nea/firmament/commands/rome.kt @@ -21,14 +21,27 @@ package moe.nea.firmament.commands import com.mojang.brigadier.CommandDispatcher import com.mojang.brigadier.arguments.StringArgumentType.getString import com.mojang.brigadier.arguments.StringArgumentType.string +import io.github.cottonmc.cotton.gui.client.CottonClientScreen +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.client.request.parameter +import io.ktor.http.URLProtocol +import io.ktor.http.path import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource +import kotlinx.coroutines.launch import net.minecraft.text.Text +import moe.nea.firmament.Firmament +import moe.nea.firmament.apis.Profiles import moe.nea.firmament.features.world.FairySouls import moe.nea.firmament.gui.config.AllConfigsGui +import moe.nea.firmament.gui.profileviewer.ProfileViewer import moe.nea.firmament.repo.ItemCostData import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData +import moe.nea.firmament.util.ScreenUtil import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.unformattedString fun firmamentCommand() = literal("firmament") { @@ -51,6 +64,31 @@ fun firmamentCommand() = literal("firmament") { } } } + thenLiteral("pv") { + thenExecute { + val me = MC.player!!.uuid + val name = MC.player!!.name.unformattedString + val names = mapOf(me to name) + source.sendFeedback(Text.translatable("firmament.pv.lookingup", name)) + Firmament.coroutineScope.launch { + val profiles = Firmament.httpClient.get { + url { + protocol = URLProtocol.HTTPS + host = "api.hypixel.net" + path("skyblock", "profiles") + parameter("key", "06b68418-71eb-4c2a-bb8a-65ed8bd4d5aa") + parameter("uuid", me.toString()) + } + }.body<Profiles>() + val profile = profiles.profiles.find { it.selected } + if (profile == null) { + source.sendFeedback(Text.translatable("firmament.pv.noprofile", name)) + return@launch + } + ScreenUtil.setScreenLater(CottonClientScreen(ProfileViewer(me, names, profile))) + } + } + } thenLiteral("price") { thenArgument("item", string()) { item -> suggestsList { RepoManager.neuRepo.items.items.keys } @@ -60,11 +98,36 @@ fun firmamentCommand() = literal("firmament") { val bazaarData = ItemCostData.bazaarData[itemName] if (bazaarData != null) { source.sendFeedback(Text.translatable("firmament.price.bazaar")) - source.sendFeedback(Text.translatable("firmament.price.bazaar.productid", bazaarData.productId.bazaarId)) - source.sendFeedback(Text.translatable("firmament.price.bazaar.buy.price", bazaarData.quickStatus.buyPrice)) - source.sendFeedback(Text.translatable("firmament.price.bazaar.buy.order", bazaarData.quickStatus.buyOrders)) - source.sendFeedback(Text.translatable("firmament.price.bazaar.sell.price", bazaarData.quickStatus.sellPrice)) - source.sendFeedback(Text.translatable("firmament.price.bazaar.sell.order", bazaarData.quickStatus.sellOrders)) + source.sendFeedback( + Text.translatable( + "firmament.price.bazaar.productid", + bazaarData.productId.bazaarId + ) + ) + source.sendFeedback( + Text.translatable( + "firmament.price.bazaar.buy.price", + bazaarData.quickStatus.buyPrice + ) + ) + source.sendFeedback( + Text.translatable( + "firmament.price.bazaar.buy.order", + bazaarData.quickStatus.buyOrders + ) + ) + source.sendFeedback( + Text.translatable( + "firmament.price.bazaar.sell.price", + bazaarData.quickStatus.sellPrice + ) + ) + source.sendFeedback( + Text.translatable( + "firmament.price.bazaar.sell.order", + bazaarData.quickStatus.sellOrders + ) + ) } val lowestBin = ItemCostData.lowestBin[itemName] if (lowestBin != null) { diff --git a/src/main/kotlin/moe/nea/firmament/gui/profileviewer/ProfileViewer.kt b/src/main/kotlin/moe/nea/firmament/gui/profileviewer/ProfileViewer.kt new file mode 100644 index 0000000..e86ce8d --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/profileviewer/ProfileViewer.kt @@ -0,0 +1,49 @@ +package moe.nea.firmament.gui.profileviewer + +import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription +import io.github.cottonmc.cotton.gui.widget.TooltipBuilder +import io.github.cottonmc.cotton.gui.widget.WGridPanel +import io.github.cottonmc.cotton.gui.widget.WTabPanel +import io.github.cottonmc.cotton.gui.widget.WText +import io.github.cottonmc.cotton.gui.widget.data.Insets +import io.github.cottonmc.cotton.gui.widget.icon.ItemIcon +import java.util.UUID +import net.minecraft.item.Items +import net.minecraft.text.Text +import moe.nea.firmament.apis.Profile +import moe.nea.firmament.apis.Skill +import moe.nea.firmament.repo.RepoManager + +class ProfileViewer( + val primaryPlayer: UUID, + val playerNames: Map<UUID, String>, + val profile: Profile, +) : LightweightGuiDescription() { + init { + val primaryMember = profile.members[primaryPlayer] ?: error("Primary player not in profile") + val panel = WTabPanel().also { rootPanel = it } + panel.backgroundPainter + panel.add(WGridPanel().also { + it.insets = Insets.ROOT_PANEL + it.add(WText(Text.literal(playerNames[primaryPlayer] ?: error("Primary player has no name"))), 0, 0, 6, 1) + for ((i, skill) in Skill.values().withIndex()) { + val leveling = RepoManager.neuRepo.constants.leveling + val exp = skill.accessor.get(primaryMember) + val maxLevel = skill.getMaximumLevel(leveling) + val level = skill.getLadder(leveling) + .runningFold(0.0) { a, b -> a + b } + .filter { it <= exp }.size + .coerceAtMost(maxLevel) + it.add(WText(Text.translatable("firmament.pv.skills.${skill.name.lowercase()}")), 0, i + 1, 5, 1) + it.add(object : WText(Text.literal("$level/$maxLevel")) { + override fun addTooltip(tooltip: TooltipBuilder) { + tooltip.add(Text.translatable("firmament.pv.skills.total", exp)) + } + }, 5, i + 1, 2, 1) + } + }) { + it.icon(ItemIcon(Items.IRON_SWORD)) + it.title(Text.translatable("firmament.pv.skills")) + } + } +} diff --git a/src/main/kotlin/moe/nea/firmament/util/json/DashlessUUIDSerializer.kt b/src/main/kotlin/moe/nea/firmament/util/json/DashlessUUIDSerializer.kt index c95b343..3dca217 100644 --- a/src/main/kotlin/moe/nea/firmament/util/json/DashlessUUIDSerializer.kt +++ b/src/main/kotlin/moe/nea/firmament/util/json/DashlessUUIDSerializer.kt @@ -2,7 +2,6 @@ package moe.nea.firmament.util.json import java.util.UUID import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializer import kotlinx.serialization.descriptors.PrimitiveKind import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor @@ -15,7 +14,11 @@ object DashlessUUIDSerializer : KSerializer<UUID> { PrimitiveSerialDescriptor("DashlessUUIDSerializer", PrimitiveKind.STRING) override fun deserialize(decoder: Decoder): UUID { - return parseDashlessUUID(decoder.decodeString()) + val str = decoder.decodeString() + if ("-" in str) { + return UUID.fromString(str) + } + return parseDashlessUUID(str) } override fun serialize(encoder: Encoder, value: UUID) { diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json index 541724f..db720a0 100644 --- a/src/main/resources/assets/firmament/lang/en_us.json +++ b/src/main/resources/assets/firmament/lang/en_us.json @@ -36,5 +36,19 @@ "firmament.key.slotlocking": "Lock Slot / Slot Binding", "firmament.key.category": "Firmament", "firmament.protectitem": "Firmament protected your item: ", - "firmament.recipe.forge.time": "Forging Time: %s" + "firmament.recipe.forge.time": "Forging Time: %s", + "firmament.pv.skills": "Skills", + "firmament.pv.skills.farming": "Farming", + "firmament.pv.skills.foraging": "Foraging", + "firmament.pv.skills.mining": "Mining", + "firmament.pv.skills.alchemy": "Alchemy", + "firmament.pv.skills.taming": "Taming", + "firmament.pv.skills.fishing": "Fishing", + "firmament.pv.skills.runecrafting": "Runecrafting", + "firmament.pv.skills.carpentry": "Carpentry", + "firmament.pv.skills.combat": "Combat", + "firmament.pv.skills.social": "Social", + "firmament.pv.skills.enchanting": "Enchanting", + "firmament.pv.skills.total": "Total Exp: %.1f", + "firmament.pv.lookingup": "Looking up %s" } |