/* * Copyright (C) 2023 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * * NotEnoughUpdates is free software: you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * NotEnoughUpdates is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with NotEnoughUpdates. If not, see . */ package io.github.moulberry.notenoughupdates.commands.misc import com.mojang.brigadier.arguments.StringArgumentType.string import io.github.moulberry.notenoughupdates.NotEnoughUpdates import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe import io.github.moulberry.notenoughupdates.events.RegisterBrigadierCommandEvent import io.github.moulberry.notenoughupdates.profileviewer.SkyblockProfiles import io.github.moulberry.notenoughupdates.util.Utils import io.github.moulberry.notenoughupdates.util.brigadier.* import net.minecraft.client.Minecraft import net.minecraft.util.ChatComponentText import net.minecraft.util.EnumChatFormatting.* import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import org.apache.commons.lang3.text.WordUtils import java.util.* import java.util.concurrent.* @NEUAutoSubscribe class PeekCommand { var future: Future<*>? = null val executor = Executors.newScheduledThreadPool(1) fun executePeek(name: String) { val chatGui = Minecraft.getMinecraft().ingameGUI.chatGUI val id = Random().nextInt(Int.MAX_VALUE / 2) + Int.MAX_VALUE / 2 fun deleteReply(text: String) { chatGui.printChatMessageWithOptionalDeletion(ChatComponentText(text), id) } deleteReply("$YELLOW[PEEK] Getting player information...") NotEnoughUpdates.profileViewer.loadPlayerByName( name ) { profile: SkyblockProfiles? -> if (profile == null) { deleteReply("$RED[PEEK] Unknown player or the Hypixel API is down.") } else { profile.resetCache() if (future?.isDone != true) { Utils.addChatMessage( "$RED[PEEK] New peek command was run, cancelling old one." ) future?.cancel(true) } deleteReply("$YELLOW[PEEK] Getting the player's SkyBlock profile(s)...") val startTime = System.currentTimeMillis() future = ForkJoinPool.commonPool().submit(object : Runnable { override fun run() { if (System.currentTimeMillis() - startTime > 10 * 1000) { deleteReply("$RED[PEEK] Getting profile info took too long, aborting.") return } val g = GRAY.toString() val profileInfo = profile.latestProfile.profileJson if (profileInfo == null) { future = executor.schedule(this, 200, TimeUnit.MILLISECONDS) return } var overallScore = 0f val isMe = name.equals("moulberry", ignoreCase = true) val stats = profile.latestProfile.stats if (stats == null) { future = executor.schedule(this, 200, TimeUnit.MILLISECONDS) return } val skyblockInfo = profile.latestProfile.levelingInfo if (NotEnoughUpdates.INSTANCE.config.profileViewer.useSoopyNetworth) { deleteReply("$YELLOW[PEEK] Getting the player's Skyblock networth...") val countDownLatch = CountDownLatch(1) profile.latestProfile.getSoopyNetworth { countDownLatch.countDown() } try { // Wait for async network request countDownLatch.await(10, TimeUnit.SECONDS) } catch (_: InterruptedException) {} // Now it's waited for network request the data should be cached (accessed in nw section) } deleteReply( "$GREEN $STRIKETHROUGH-=-$RESET$GREEN ${ Utils.getElementAsString( profile.hypixelProfile!!["displayname"], name ) }'s Info $STRIKETHROUGH-=-" ) if (skyblockInfo == null || !profile.latestProfile.skillsApiEnabled()) { Utils.addChatMessage(YELLOW.toString() + "Skills API disabled!") } else { var totalSkillLVL = 0f var totalSkillCount = 0f val skills: List = mutableListOf( "taming", "mining", "foraging", "enchanting", "farming", "combat", "fishing", "alchemy", "carpentry" ) for (skillName in skills) { totalSkillLVL += skyblockInfo[skillName]!!.level totalSkillCount++ } var combat = skyblockInfo["combat"]!!.level var zombie = skyblockInfo["zombie"]!!.level var spider = skyblockInfo["spider"]!!.level var wolf = skyblockInfo["wolf"]!!.level var enderman = skyblockInfo["enderman"]!!.level var blaze = skyblockInfo["blaze"]!!.level var avgSkillLVL = totalSkillLVL / totalSkillCount if (isMe) { avgSkillLVL = 6f combat = 4f zombie = 2f spider = 1f wolf = 2f enderman = 0f blaze = 0f } val combatPrefix = if (combat > 20) (if (combat > 35) GREEN else YELLOW) else RED val zombiePrefix = if (zombie > 3) (if (zombie > 6) GREEN else YELLOW) else RED val spiderPrefix = if (spider > 3) (if (spider > 6) GREEN else YELLOW) else RED val wolfPrefix = if (wolf > 3) (if (wolf > 6) GREEN else YELLOW) else RED val endermanPrefix = if (enderman > 3) (if (enderman > 6) GREEN else YELLOW) else RED val blazePrefix = if (blaze > 3) (if (blaze > 6) GREEN else YELLOW) else RED val avgPrefix = if (avgSkillLVL > 20) (if (avgSkillLVL > 35) GREEN else YELLOW) else RED overallScore += zombie * zombie / 81f overallScore += spider * spider / 81f overallScore += wolf * wolf / 81f overallScore += enderman * enderman / 81f overallScore += blaze * blaze / 81f overallScore += avgSkillLVL / 20f val cata = skyblockInfo["catacombs"]!!.level.toInt() val cataPrefix = if (cata > 15) (if (cata > 25) GREEN else YELLOW) else RED overallScore += cata * cata / 2000f Utils.addChatMessage( g + "Combat: " + combatPrefix + Math.floor(combat.toDouble()) .toInt() + (if (cata > 0) "$g - Cata: $cataPrefix$cata" else "") + g + " - AVG: " + avgPrefix + Math.floor(avgSkillLVL.toDouble()) .toInt() ) Utils.addChatMessage( g + "Slayer: " + zombiePrefix + Math.floor(zombie.toDouble()) .toInt() + g + "-" + spiderPrefix + Math.floor(spider.toDouble()) .toInt() + g + "-" + wolfPrefix + Math.floor(wolf.toDouble()).toInt() + g + "-" + endermanPrefix + Math.floor(enderman.toDouble()) .toInt() + g + "-" + blazePrefix + Math.floor(blaze.toDouble()).toInt() ) } val health = stats["health"].toInt() val defence = stats["defence"].toInt() val strength = stats["strength"].toInt() val intelligence = stats["intelligence"].toInt() val healthPrefix = if (health > 800) (if (health > 1600) GREEN else YELLOW) else RED val defencePrefix = if (defence > 200) (if (defence > 600) GREEN else YELLOW) else RED val strengthPrefix = if (strength > 100) (if (strength > 300) GREEN else YELLOW) else RED val intelligencePrefix = if (intelligence > 300) (if (intelligence > 900) GREEN else YELLOW) else RED Utils.addChatMessage( g + "Stats : " + healthPrefix + health + RED + "\u2764 " + defencePrefix + defence + GREEN + "\u2748 " + strengthPrefix + strength + RED + "\u2741 " + intelligencePrefix + intelligence + AQUA + "\u270e " ) val bankBalance = Utils.getElementAsFloat( Utils.getElement( profileInfo, "banking.balance" ), -1f ) val purseBalance = Utils.getElementAsFloat( Utils.getElement( profileInfo, "coin_purse" ), 0f ) val networth = if (NotEnoughUpdates.INSTANCE.config.profileViewer.useSoopyNetworth) { val nwData = profile.latestProfile.getSoopyNetworth {} nwData?.networth ?: -2L } else { profile.latestProfile.networth } val money = Math.max(bankBalance + purseBalance, networth.toFloat()) val moneyPrefix = if (money > 50 * 1000 * 1000) (if (money > 200 * 1000 * 1000) GREEN else YELLOW) else RED Utils.addChatMessage( g + "Purse: " + moneyPrefix + Utils.shortNumberFormat( purseBalance.toDouble(), 0 ) + g + " - Bank: " + (if (bankBalance == -1f) YELLOW.toString() + "N/A" else moneyPrefix.toString() + if (isMe) "4.8b" else Utils.shortNumberFormat( bankBalance.toDouble(), 0 )) + if (networth > 0) "$g - Net: $moneyPrefix" + Utils.shortNumberFormat( networth.toDouble(), 0 ) else "" ) overallScore += Math.min(2f, money / (100f * 1000 * 1000)) val activePet = Utils.getElementAsString( Utils.getElement( profile.latestProfile.petsInfo, "active_pet.type" ), "None Active" ) val activePetTier = Utils.getElementAsString( Utils.getElement( profile.latestProfile.petsInfo, "active_pet.tier" ), "UNKNOWN" ) var col = NotEnoughUpdates.petRarityToColourMap[activePetTier] if (col == null) col = LIGHT_PURPLE.toString() Utils.addChatMessage( g + "Pet : " + col + WordUtils.capitalizeFully( activePet.replace("_", " ") ) ) var overall = "Skywars Main" if (isMe) { overall = Utils.chromaString("Literally the best player to exist") // ego much } else if (overallScore < 5 && bankBalance + purseBalance > 500 * 1000 * 1000) { overall = GOLD.toString() + "Bill Gates" } else if (overallScore > 9) { overall = Utils.chromaString("Didn't even think this score was possible") } else if (overallScore > 8) { overall = Utils.chromaString("Mentally unstable") } else if (overallScore > 7) { overall = GOLD.toString() + "Why though 0.0" } else if (overallScore > 5.5) { overall = GOLD.toString() + "Bro stop playing" } else if (overallScore > 4) { overall = GREEN.toString() + "Kinda sweaty" } else if (overallScore > 3) { overall = YELLOW.toString() + "Alright I guess" } else if (overallScore > 2) { overall = YELLOW.toString() + "Ender Non" } else if (overallScore > 1) { overall = RED.toString() + "Played SkyBlock" } Utils.addChatMessage( g + "Overall score: " + overall + g + " (" + Math.round( overallScore * 10 ) / 10f + ")" ) } }) } } } @SubscribeEvent fun onCommand(event: RegisterBrigadierCommandEvent) { event.command("peek") { thenArgument("player", string()) { player -> suggestsList { Minecraft.getMinecraft().theWorld.playerEntities.map { it.name } } thenExecute { executePeek(this[player]) } }.withHelp("Quickly glance at other peoples stats") thenExecute { executePeek(Minecraft.getMinecraft().thePlayer.name) } }.withHelp("Quickly glance at your own stats") } }