feat(internal): Add a tab list api
This commit is contained in:
@@ -12,6 +12,7 @@ import moe.nea.firmament.apis.UrsaManager
|
||||
import moe.nea.firmament.events.CommandEvent
|
||||
import moe.nea.firmament.events.FirmamentEventBus
|
||||
import moe.nea.firmament.features.debug.DebugLogger
|
||||
import moe.nea.firmament.features.debug.DeveloperFeatures
|
||||
import moe.nea.firmament.features.debug.PowerUserTools
|
||||
import moe.nea.firmament.features.inventory.buttons.InventoryButtons
|
||||
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
|
||||
@@ -202,7 +203,7 @@ fun firmamentCommand() = literal("firmament") {
|
||||
}
|
||||
}
|
||||
}
|
||||
thenLiteral("dev") {
|
||||
thenLiteral(DeveloperFeatures.DEVELOPER_SUBCOMMAND) {
|
||||
thenLiteral("simulate") {
|
||||
thenArgument("message", RestArgumentType) { message ->
|
||||
thenExecute {
|
||||
|
||||
@@ -62,7 +62,7 @@ object AnimatedClothingScanner {
|
||||
|
||||
@Subscribe
|
||||
fun onSubCommand(event: CommandEvent.SubCommand) {
|
||||
event.subcommand("dev") {
|
||||
event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) {
|
||||
thenLiteral("stealthisfit") {
|
||||
thenLiteral("clear") {
|
||||
thenExecute {
|
||||
|
||||
@@ -25,6 +25,7 @@ import moe.nea.firmament.util.asm.AsmAnnotationUtil
|
||||
import moe.nea.firmament.util.iterate
|
||||
|
||||
object DeveloperFeatures : FirmamentFeature {
|
||||
val DEVELOPER_SUBCOMMAND: String = "dev"
|
||||
override val identifier: String
|
||||
get() = "developer"
|
||||
override val config: TConfig
|
||||
@@ -103,9 +104,12 @@ object DeveloperFeatures : FirmamentFeature {
|
||||
MC.sendChat(Text.translatable("firmament.dev.resourcerebuild.start"))
|
||||
val startTime = TimeMark.now()
|
||||
process.toHandle().onExit().thenApply {
|
||||
MC.sendChat(Text.stringifiedTranslatable(
|
||||
"firmament.dev.resourcerebuild.done",
|
||||
startTime.passedTime()))
|
||||
MC.sendChat(
|
||||
Text.stringifiedTranslatable(
|
||||
"firmament.dev.resourcerebuild.done",
|
||||
startTime.passedTime()
|
||||
)
|
||||
)
|
||||
Unit
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,7 @@ object SoundVisualizer {
|
||||
|
||||
@Subscribe
|
||||
fun onSubCommand(event: CommandEvent.SubCommand) {
|
||||
event.subcommand("dev") {
|
||||
event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) {
|
||||
thenLiteral("sounds") {
|
||||
thenExecute {
|
||||
showSounds = !showSounds
|
||||
|
||||
@@ -26,6 +26,7 @@ import moe.nea.firmament.commands.thenExecute
|
||||
import moe.nea.firmament.commands.thenLiteral
|
||||
import moe.nea.firmament.events.CommandEvent
|
||||
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
|
||||
import moe.nea.firmament.features.debug.DeveloperFeatures
|
||||
import moe.nea.firmament.features.debug.ExportedTestConstantMeta
|
||||
import moe.nea.firmament.features.debug.PowerUserTools
|
||||
import moe.nea.firmament.repo.RepoDownloadManager
|
||||
@@ -97,7 +98,7 @@ object ItemExporter {
|
||||
|
||||
@Subscribe
|
||||
fun onCommand(event: CommandEvent.SubCommand) {
|
||||
event.subcommand("dev") {
|
||||
event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) {
|
||||
thenLiteral("reexportlore") {
|
||||
thenArgument("itemid", StringArgumentType.string()) { itemid ->
|
||||
suggestsList { RepoManager.neuRepo.items.items.keys }
|
||||
|
||||
@@ -9,6 +9,8 @@ object StringUtil {
|
||||
return string.replace(",", "").toInt()
|
||||
}
|
||||
|
||||
fun String.title() = replaceFirstChar { it.titlecase() }
|
||||
|
||||
fun Iterable<String>.unwords() = joinToString(" ")
|
||||
fun nextLexicographicStringOfSameLength(string: String): String {
|
||||
val next = StringBuilder(string)
|
||||
|
||||
96
src/main/kotlin/util/mc/MCTabListAPI.kt
Normal file
96
src/main/kotlin/util/mc/MCTabListAPI.kt
Normal file
@@ -0,0 +1,96 @@
|
||||
package moe.nea.firmament.util.mc
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import java.util.Optional
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import net.minecraft.client.gui.hud.PlayerListHud
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.scoreboard.Team
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.text.TextCodecs
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.commands.thenExecute
|
||||
import moe.nea.firmament.commands.thenLiteral
|
||||
import moe.nea.firmament.events.CommandEvent
|
||||
import moe.nea.firmament.events.TickEvent
|
||||
import moe.nea.firmament.features.debug.DeveloperFeatures
|
||||
import moe.nea.firmament.features.debug.ExportedTestConstantMeta
|
||||
import moe.nea.firmament.mixins.accessor.AccessorPlayerListHud
|
||||
import moe.nea.firmament.util.ClipboardUtils
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.intoOptional
|
||||
import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString
|
||||
|
||||
object MCTabListAPI {
|
||||
|
||||
fun PlayerListHud.cast() = this as AccessorPlayerListHud
|
||||
|
||||
@Subscribe
|
||||
fun onTick(event: TickEvent) {
|
||||
_currentTabList = null
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun devCommand(event: CommandEvent.SubCommand) {
|
||||
event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) {
|
||||
thenLiteral("copytablist") {
|
||||
thenExecute {
|
||||
currentTabList.body.forEach {
|
||||
MC.sendChat(Text.literal(TextCodecs.CODEC.encodeStart(NbtOps.INSTANCE, it).orThrow.toString()))
|
||||
}
|
||||
var compound = CurrentTabList.CODEC.encodeStart(NbtOps.INSTANCE, currentTabList).orThrow
|
||||
compound = ExportedTestConstantMeta.SOURCE_CODEC.encode(
|
||||
ExportedTestConstantMeta.current,
|
||||
NbtOps.INSTANCE,
|
||||
compound
|
||||
).orThrow
|
||||
ClipboardUtils.setTextContent(
|
||||
compound.toPrettyString()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@get:TestOnly
|
||||
@set:TestOnly
|
||||
var _currentTabList: CurrentTabList? = null
|
||||
|
||||
val currentTabList get() = _currentTabList ?: getTabListNow().also { _currentTabList = it }
|
||||
|
||||
data class CurrentTabList(
|
||||
val header: Optional<Text>,
|
||||
val footer: Optional<Text>,
|
||||
val body: List<Text>,
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<CurrentTabList> = RecordCodecBuilder.create {
|
||||
it.group(
|
||||
TextCodecs.CODEC.optionalFieldOf("header").forGetter(CurrentTabList::header),
|
||||
TextCodecs.CODEC.optionalFieldOf("footer").forGetter(CurrentTabList::footer),
|
||||
TextCodecs.CODEC.listOf().fieldOf("body").forGetter(CurrentTabList::body),
|
||||
).apply(it, ::CurrentTabList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTabListNow(): CurrentTabList {
|
||||
// This is a precondition for PlayerListHud.collectEntries to be valid
|
||||
MC.networkHandler ?: return CurrentTabList(Optional.empty(), Optional.empty(), emptyList())
|
||||
val hud = MC.inGameHud.playerListHud.cast()
|
||||
val entries = hud.collectPlayerEntries_firmament()
|
||||
.map {
|
||||
it.displayName ?: run {
|
||||
val team = it.scoreboardTeam
|
||||
val name = it.profile.name
|
||||
Team.decorateName(team, Text.literal(name))
|
||||
}
|
||||
}
|
||||
return CurrentTabList(
|
||||
header = hud.header_firmament.intoOptional(),
|
||||
footer = hud.footer_firmament.intoOptional(),
|
||||
body = entries,
|
||||
)
|
||||
}
|
||||
}
|
||||
41
src/main/kotlin/util/skyblock/TabListAPI.kt
Normal file
41
src/main/kotlin/util/skyblock/TabListAPI.kt
Normal file
@@ -0,0 +1,41 @@
|
||||
package moe.nea.firmament.util.skyblock
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.util.StringUtil.title
|
||||
import moe.nea.firmament.util.StringUtil.unwords
|
||||
import moe.nea.firmament.util.mc.MCTabListAPI
|
||||
import moe.nea.firmament.util.unformattedString
|
||||
|
||||
object TabListAPI {
|
||||
|
||||
fun getWidgetLines(widgetName: WidgetName, includeTitle: Boolean = false, from: MCTabListAPI.CurrentTabList = MCTabListAPI.currentTabList): List<Text> {
|
||||
return from.body
|
||||
.dropWhile { !widgetName.matchesTitle(it) }
|
||||
.takeWhile { it.string.isNotBlank() && !it.string.startsWith(" ") }
|
||||
.let { if (includeTitle) it else it.drop(1) }
|
||||
}
|
||||
|
||||
enum class WidgetName(regex: Regex?) {
|
||||
COMMISSIONS,
|
||||
SKILLS("Skills:( .*)?"),
|
||||
PROFILE("Profile: (.*)"),
|
||||
COLLECTION,
|
||||
ESSENCE,
|
||||
PET
|
||||
;
|
||||
|
||||
fun matchesTitle(it: Text): Boolean {
|
||||
return regex.matches(it.unformattedString)
|
||||
}
|
||||
|
||||
constructor() : this(null)
|
||||
constructor(@Language("RegExp") regex: String) : this(Regex(regex))
|
||||
|
||||
val label =
|
||||
name.split("_").map { it.lowercase().title() }.unwords()
|
||||
val regex = regex ?: Regex.fromLiteral("$label:")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user