diff options
author | Linnea Gräf <nea@nea.moe> | 2025-05-07 23:09:10 +0200 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2025-05-07 23:09:10 +0200 |
commit | 63669bc28be11adbf55c8d49bb747bb22124be86 (patch) | |
tree | d77c8e5a7e32985ae1402eba16544a49d3c163e9 /src/main/kotlin/features/debug | |
parent | 38fd61fdcc70f75f5b8b5eb39e21c34aaf5ceb90 (diff) | |
download | Firmament-63669bc28be11adbf55c8d49bb747bb22124be86.tar.gz Firmament-63669bc28be11adbf55c8d49bb747bb22124be86.tar.bz2 Firmament-63669bc28be11adbf55c8d49bb747bb22124be86.zip |
feat: Add more complex entity equipment scraper
Diffstat (limited to 'src/main/kotlin/features/debug')
-rw-r--r-- | src/main/kotlin/features/debug/AnimatedClothingScanner.kt | 183 |
1 files changed, 133 insertions, 50 deletions
diff --git a/src/main/kotlin/features/debug/AnimatedClothingScanner.kt b/src/main/kotlin/features/debug/AnimatedClothingScanner.kt index 47da7d6..9f9f135 100644 --- a/src/main/kotlin/features/debug/AnimatedClothingScanner.kt +++ b/src/main/kotlin/features/debug/AnimatedClothingScanner.kt @@ -2,13 +2,12 @@ package moe.nea.firmament.features.debug import net.minecraft.command.argument.RegistryKeyArgumentType import net.minecraft.component.ComponentType -import net.minecraft.component.DataComponentTypes import net.minecraft.entity.Entity +import net.minecraft.entity.decoration.ArmorStandEntity import net.minecraft.item.ItemStack import net.minecraft.nbt.NbtElement import net.minecraft.nbt.NbtOps import net.minecraft.registry.RegistryKeys -import net.minecraft.util.Identifier import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.commands.get import moe.nea.firmament.commands.thenArgument @@ -16,16 +15,17 @@ import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.commands.thenLiteral import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.EntityUpdateEvent +import moe.nea.firmament.events.WorldReadyEvent import moe.nea.firmament.util.ClipboardUtils import moe.nea.firmament.util.MC +import moe.nea.firmament.util.math.GChainReconciliation +import moe.nea.firmament.util.math.GChainReconciliation.shortenCycle import moe.nea.firmament.util.mc.NbtPrism -import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.tr object AnimatedClothingScanner { - data class SubjectOfFashionTheft<T>( - val observedEntity: Entity, + data class LensOfFashionTheft<T>( val prism: NbtPrism, val component: ComponentType<T>, ) { @@ -36,75 +36,158 @@ object AnimatedClothingScanner { } } - var subject: SubjectOfFashionTheft<*>? = null + var lens: LensOfFashionTheft<*>? = null + var subject: Entity? = null + var history: MutableList<String> = mutableListOf() + val metaHistory: MutableList<List<String>> = mutableListOf() @OptIn(ExperimentalStdlibApi::class) @Subscribe fun onUpdate(event: EntityUpdateEvent) { val s = subject ?: return - if (event.entity != s.observedEntity) return + if (event.entity != s) return + val l = lens ?: return if (event is EntityUpdateEvent.EquipmentUpdate) { - val lines = mutableListOf<String>() event.newEquipment.forEach { - val formatted = (s.observe(it.second)).joinToString() - lines.add(formatted) - MC.sendChat( - tr( - "firmament.fitstealer.update", - "[FIT CHECK][${MC.currentTick}] ${it.first.asString()} => $formatted" - ) - ) - } - if (lines.isNotEmpty()) { - val contents = ClipboardUtils.getTextContents() - if (contents.startsWith(EXPORT_WATERMARK)) - ClipboardUtils.setTextContent( - contents + "\n" + lines.joinToString("\n") - ) + val formatted = (l.observe(it.second)).joinToString() + history.add(formatted) + // TODO: add a slot filter } } } - val EXPORT_WATERMARK = "[CLOTHES EXPORT]" + fun reduceHistory(reducer: (List<String>, List<String>) -> List<String>): List<String> { + return metaHistory.fold(history, reducer).shortenCycle() + } @Subscribe fun onSubCommand(event: CommandEvent.SubCommand) { event.subcommand("dev") { thenLiteral("stealthisfit") { - thenArgument( - "component", - RegistryKeyArgumentType.registryKey(RegistryKeys.DATA_COMPONENT_TYPE) - ) { component -> - thenArgument("path", NbtPrism.Argument) { path -> + thenLiteral("clear") { + thenExecute { + subject = null + metaHistory.clear() + history.clear() + MC.sendChat(tr("firmament.fitstealer.clear", "Cleared fit stealing history")) + } + } + thenLiteral("copy") { + thenExecute { + val history = reduceHistory { a, b -> a + b } + copyHistory(history) + MC.sendChat(tr("firmament.fitstealer.copied", "Copied the history")) + } + thenLiteral("deduplicated") { thenExecute { - subject = - if (subject == null) run { - val entity = MC.instance.targetedEntity ?: return@run null - val clipboard = ClipboardUtils.getTextContents() - if (!clipboard.startsWith(EXPORT_WATERMARK)) { - ClipboardUtils.setTextContent(EXPORT_WATERMARK) - } else { - ClipboardUtils.setTextContent("$clipboard\n\n[NEW SCANNER]") - } - SubjectOfFashionTheft( - entity, - get(path), - MC.unsafeGetRegistryEntry(get(component))!!, - ) - } else null - + val history = reduceHistory { a, b -> + (a.toMutableSet() + b).toList() + } + copyHistory(history) MC.sendChat( - subject?.let { + tr( + "firmament.fitstealer.copied.deduplicated", + "Copied the deduplicated history" + ) + ) + } + } + thenLiteral("merged") { + thenExecute { + val history = reduceHistory(GChainReconciliation::reconcileCycles) + copyHistory(history) + MC.sendChat(tr("firmament.fitstealer.copied.merged", "Copied the merged history")) + } + } + } + thenLiteral("target") { + thenLiteral("self") { + thenExecute { + toggleObserve(MC.player!!) + } + } + thenLiteral("pet") { + thenExecute { + source.sendFeedback( + tr( + "firmament.fitstealer.stealingpet", + "Observing nearest marker armourstand" + ) + ) + val p = MC.player!! + val nearestPet = p.world.getEntitiesByClass( + ArmorStandEntity::class.java, + p.boundingBox.expand(10.0), + { it.isMarker }) + .minBy { it.squaredDistanceTo(p) } + toggleObserve(nearestPet) + } + } + thenExecute { + val ent = MC.instance.targetedEntity + if (ent == null) { + source.sendFeedback( + tr( + "firmament.fitstealer.notargetundercursor", + "No entity under cursor" + ) + ) + } else { + toggleObserve(ent) + } + } + } + thenLiteral("path") { + thenArgument( + "component", + RegistryKeyArgumentType.registryKey(RegistryKeys.DATA_COMPONENT_TYPE) + ) { component -> + thenArgument("path", NbtPrism.Argument) { path -> + thenExecute { + lens = LensOfFashionTheft( + get(path), + MC.unsafeGetRegistryEntry(get(component))!!, + ) + source.sendFeedback( tr( - "firmament.fitstealer.targeted", - "Observing the equipment of ${it.observedEntity.name}." + "firmament.fitstealer.lensset", + "Analyzing path ${get(path)} for component ${get(component).value}" ) - } ?: tr("firmament.fitstealer.targetlost", "No longer logging equipment."), - ) + ) + } } } } } } } + + private fun copyHistory(toCopy: List<String>) { + ClipboardUtils.setTextContent(toCopy.joinToString("\n")) + } + + @Subscribe + fun onWorldSwap(event: WorldReadyEvent) { + subject = null + if (history.isNotEmpty()) { + metaHistory.add(history) + history = mutableListOf() + } + } + + private fun toggleObserve(entity: Entity?) { + subject = if (subject == null) entity else null + if (subject == null) { + metaHistory.add(history) + history = mutableListOf() + } + MC.sendChat( + subject?.let { + tr( + "firmament.fitstealer.targeted", + "Observing the equipment of ${it.name}." + ) + } ?: tr("firmament.fitstealer.targetlost", "No longer logging equipment."), + ) + } } |