feat(dev): add more elaborate automatic texture exporter (stealthisfit)
This commit is contained in:
@@ -1,51 +1,111 @@
|
|||||||
package moe.nea.firmament.features.debug
|
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.component.DataComponentTypes
|
||||||
import net.minecraft.entity.Entity
|
import net.minecraft.entity.Entity
|
||||||
|
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.annotations.Subscribe
|
||||||
|
import moe.nea.firmament.commands.get
|
||||||
|
import moe.nea.firmament.commands.thenArgument
|
||||||
import moe.nea.firmament.commands.thenExecute
|
import moe.nea.firmament.commands.thenExecute
|
||||||
import moe.nea.firmament.commands.thenLiteral
|
import moe.nea.firmament.commands.thenLiteral
|
||||||
import moe.nea.firmament.events.CommandEvent
|
import moe.nea.firmament.events.CommandEvent
|
||||||
import moe.nea.firmament.events.EntityUpdateEvent
|
import moe.nea.firmament.events.EntityUpdateEvent
|
||||||
|
import moe.nea.firmament.util.ClipboardUtils
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.mc.NbtPrism
|
||||||
import moe.nea.firmament.util.skyBlockId
|
import moe.nea.firmament.util.skyBlockId
|
||||||
import moe.nea.firmament.util.tr
|
import moe.nea.firmament.util.tr
|
||||||
|
|
||||||
object AnimatedClothingScanner {
|
object AnimatedClothingScanner {
|
||||||
|
|
||||||
var observedEntity: Entity? = null
|
data class SubjectOfFashionTheft<T>(
|
||||||
|
val observedEntity: Entity,
|
||||||
|
val prism: NbtPrism,
|
||||||
|
val component: ComponentType<T>,
|
||||||
|
) {
|
||||||
|
fun observe(itemStack: ItemStack): Collection<NbtElement> {
|
||||||
|
val x = itemStack.get(component) ?: return listOf()
|
||||||
|
val nbt = component.codecOrThrow.encodeStart(NbtOps.INSTANCE, x).orThrow
|
||||||
|
return prism.access(nbt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var subject: SubjectOfFashionTheft<*>? = null
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onUpdate(event: EntityUpdateEvent) {
|
fun onUpdate(event: EntityUpdateEvent) {
|
||||||
if (event.entity != observedEntity) return
|
val s = subject ?: return
|
||||||
|
if (event.entity != s.observedEntity) return
|
||||||
if (event is EntityUpdateEvent.EquipmentUpdate) {
|
if (event is EntityUpdateEvent.EquipmentUpdate) {
|
||||||
|
val lines = mutableListOf<String>()
|
||||||
event.newEquipment.forEach {
|
event.newEquipment.forEach {
|
||||||
val id = it.second.skyBlockId?.neuItem
|
val formatted = (s.observe(it.second)).joinToString()
|
||||||
val colour = it.second.get(DataComponentTypes.DYED_COLOR)
|
lines.add(formatted)
|
||||||
?.rgb?.toHexString(HexFormat.UpperCase)
|
MC.sendChat(
|
||||||
?.let { " #$it" } ?: ""
|
tr(
|
||||||
MC.sendChat(tr("firmament.fitstealer.update",
|
"firmament.fitstealer.update",
|
||||||
"[FIT CHECK][${MC.currentTick}] ${it.first.asString()} => ${id}${colour}"))
|
"[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 EXPORT_WATERMARK = "[CLOTHES EXPORT]"
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onSubCommand(event: CommandEvent.SubCommand) {
|
fun onSubCommand(event: CommandEvent.SubCommand) {
|
||||||
event.subcommand("dev") {
|
event.subcommand("dev") {
|
||||||
thenLiteral("stealthisfit") {
|
thenLiteral("stealthisfit") {
|
||||||
|
thenArgument(
|
||||||
|
"component",
|
||||||
|
RegistryKeyArgumentType.registryKey(RegistryKeys.DATA_COMPONENT_TYPE)
|
||||||
|
) { component ->
|
||||||
|
thenArgument("path", NbtPrism.Argument) { path ->
|
||||||
thenExecute {
|
thenExecute {
|
||||||
observedEntity =
|
subject =
|
||||||
if (observedEntity == null) MC.instance.targetedEntity else null
|
if (subject == null) run {
|
||||||
|
val entity = MC.instance.targetedEntity ?: return@run null
|
||||||
|
val clipboard = ClipboardUtils.getTextContents()
|
||||||
|
MC.instance.entit
|
||||||
|
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
|
||||||
|
|
||||||
MC.sendChat(
|
MC.sendChat(
|
||||||
observedEntity?.let {
|
subject?.let {
|
||||||
tr("firmament.fitstealer.targeted", "Observing the equipment of ${it.name}.")
|
tr(
|
||||||
|
"firmament.fitstealer.targeted",
|
||||||
|
"Observing the equipment of ${it.observedEntity.name}."
|
||||||
|
)
|
||||||
} ?: tr("firmament.fitstealer.targetlost", "No longer logging equipment."),
|
} ?: tr("firmament.fitstealer.targetlost", "No longer logging equipment."),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package moe.nea.firmament.util
|
|||||||
|
|
||||||
import io.github.moulberry.repo.data.Coordinate
|
import io.github.moulberry.repo.data.Coordinate
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.hud.InGameHud
|
import net.minecraft.client.gui.hud.InGameHud
|
||||||
import net.minecraft.client.gui.screen.Screen
|
import net.minecraft.client.gui.screen.Screen
|
||||||
@@ -16,10 +17,14 @@ import net.minecraft.item.Item
|
|||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
|
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
|
||||||
import net.minecraft.registry.BuiltinRegistries
|
import net.minecraft.registry.BuiltinRegistries
|
||||||
|
import net.minecraft.registry.Registry
|
||||||
|
import net.minecraft.registry.RegistryKey
|
||||||
import net.minecraft.registry.RegistryKeys
|
import net.minecraft.registry.RegistryKeys
|
||||||
import net.minecraft.registry.RegistryWrapper
|
import net.minecraft.registry.RegistryWrapper
|
||||||
|
import net.minecraft.registry.entry.RegistryEntry
|
||||||
import net.minecraft.resource.ReloadableResourceManagerImpl
|
import net.minecraft.resource.ReloadableResourceManagerImpl
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import moe.nea.firmament.events.TickEvent
|
import moe.nea.firmament.events.TickEvent
|
||||||
@@ -120,6 +125,19 @@ object MC {
|
|||||||
return field
|
return field
|
||||||
}
|
}
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
|
fun <T> unsafeGetRegistryEntry(registry: RegistryKey<out Registry<T>>, identifier: Identifier) =
|
||||||
|
unsafeGetRegistryEntry(RegistryKey.of(registry, identifier))
|
||||||
|
|
||||||
|
|
||||||
|
fun <T> unsafeGetRegistryEntry(registryKey: RegistryKey<T>): T? {
|
||||||
|
return currentOrDefaultRegistries
|
||||||
|
.getOrThrow(registryKey.registryRef)
|
||||||
|
.getOptional(registryKey)
|
||||||
|
.getOrNull()
|
||||||
|
?.value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
91
src/main/kotlin/util/mc/NbtPrism.kt
Normal file
91
src/main/kotlin/util/mc/NbtPrism.kt
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package moe.nea.firmament.util.mc
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonElement
|
||||||
|
import com.google.gson.JsonPrimitive
|
||||||
|
import com.mojang.brigadier.StringReader
|
||||||
|
import com.mojang.brigadier.arguments.ArgumentType
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType
|
||||||
|
import com.mojang.brigadier.context.CommandContext
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder
|
||||||
|
import com.mojang.serialization.JsonOps
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import kotlin.collections.indices
|
||||||
|
import kotlin.collections.map
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.nbt.NbtElement
|
||||||
|
import net.minecraft.nbt.NbtList
|
||||||
|
import net.minecraft.nbt.NbtOps
|
||||||
|
import net.minecraft.nbt.NbtString
|
||||||
|
import moe.nea.firmament.util.Base64Util
|
||||||
|
|
||||||
|
class NbtPrism(val path: List<String>) {
|
||||||
|
companion object {
|
||||||
|
fun fromElement(path: JsonElement): NbtPrism? {
|
||||||
|
if (path is JsonArray) {
|
||||||
|
return NbtPrism(path.map { (it as JsonPrimitive).asString })
|
||||||
|
} else if (path is JsonPrimitive && path.isString) {
|
||||||
|
return NbtPrism(path.asString.split("."))
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Argument : ArgumentType<NbtPrism> {
|
||||||
|
override fun parse(reader: StringReader): NbtPrism? {
|
||||||
|
return fromElement(JsonPrimitive(StringArgumentType.string().parse(reader)))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExamples(): Collection<String?>? {
|
||||||
|
return listOf("some.nbt.path", "some.other.*", "some.path.*json.in.a.json.string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Prism($path)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun access(root: NbtElement): Collection<NbtElement> {
|
||||||
|
var rootSet = mutableListOf(root)
|
||||||
|
var switch = mutableListOf<NbtElement>()
|
||||||
|
for (pathSegment in path) {
|
||||||
|
if (pathSegment == ".") continue
|
||||||
|
if (pathSegment != "*" && pathSegment.startsWith("*")) {
|
||||||
|
if (pathSegment == "*json") {
|
||||||
|
for (element in rootSet) {
|
||||||
|
val eString = element.asString().getOrNull() ?: continue
|
||||||
|
val element = Gson().fromJson(eString, JsonElement::class.java)
|
||||||
|
switch.add(JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, element))
|
||||||
|
}
|
||||||
|
} else if (pathSegment == "*base64") {
|
||||||
|
for (element in rootSet) {
|
||||||
|
val string = element.asString().getOrNull() ?: continue
|
||||||
|
switch.add(NbtString.of(Base64Util.decodeString(string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (element in rootSet) {
|
||||||
|
if (element is NbtList) {
|
||||||
|
if (pathSegment == "*")
|
||||||
|
switch.addAll(element)
|
||||||
|
val index = pathSegment.toIntOrNull() ?: continue
|
||||||
|
if (index !in element.indices) continue
|
||||||
|
switch.add(element[index])
|
||||||
|
}
|
||||||
|
if (element is NbtCompound) {
|
||||||
|
if (pathSegment == "*")
|
||||||
|
element.keys.mapTo(switch) { element.get(it)!! }
|
||||||
|
switch.add(element.get(pathSegment) ?: continue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val temp = switch
|
||||||
|
switch = rootSet
|
||||||
|
rootSet = temp
|
||||||
|
switch.clear()
|
||||||
|
}
|
||||||
|
return rootSet
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +1,24 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.features.texturepack.predicates
|
package moe.nea.firmament.features.texturepack.predicates
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonPrimitive
|
import com.google.gson.JsonPrimitive
|
||||||
import kotlin.jvm.optionals.getOrDefault
|
import kotlin.jvm.optionals.getOrDefault
|
||||||
import kotlin.jvm.optionals.getOrNull
|
import kotlin.jvm.optionals.getOrNull
|
||||||
import com.mojang.serialization.JsonOps
|
|
||||||
import moe.nea.firmament.features.texturepack.FirmamentModelPredicate
|
import moe.nea.firmament.features.texturepack.FirmamentModelPredicate
|
||||||
import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser
|
import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser
|
||||||
import moe.nea.firmament.features.texturepack.StringMatcher
|
import moe.nea.firmament.features.texturepack.StringMatcher
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtByte
|
import net.minecraft.nbt.NbtByte
|
||||||
import net.minecraft.nbt.NbtCompound
|
|
||||||
import net.minecraft.nbt.NbtDouble
|
import net.minecraft.nbt.NbtDouble
|
||||||
import net.minecraft.nbt.NbtElement
|
import net.minecraft.nbt.NbtElement
|
||||||
import net.minecraft.nbt.NbtFloat
|
import net.minecraft.nbt.NbtFloat
|
||||||
import net.minecraft.nbt.NbtInt
|
import net.minecraft.nbt.NbtInt
|
||||||
import net.minecraft.nbt.NbtList
|
|
||||||
import net.minecraft.nbt.NbtLong
|
import net.minecraft.nbt.NbtLong
|
||||||
import net.minecraft.nbt.NbtOps
|
|
||||||
import net.minecraft.nbt.NbtShort
|
import net.minecraft.nbt.NbtShort
|
||||||
import net.minecraft.nbt.NbtString
|
|
||||||
import moe.nea.firmament.util.Base64Util
|
|
||||||
import moe.nea.firmament.util.extraAttributes
|
import moe.nea.firmament.util.extraAttributes
|
||||||
|
import moe.nea.firmament.util.mc.NbtPrism
|
||||||
|
|
||||||
fun interface NbtMatcher {
|
fun interface NbtMatcher {
|
||||||
fun matches(nbt: NbtElement): Boolean
|
fun matches(nbt: NbtElement): Boolean
|
||||||
@@ -246,60 +239,3 @@ data class ExtraAttributesPredicate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NbtPrism(val path: List<String>) {
|
|
||||||
companion object {
|
|
||||||
fun fromElement(path: JsonElement): NbtPrism? {
|
|
||||||
if (path is JsonArray) {
|
|
||||||
return NbtPrism(path.map { (it as JsonPrimitive).asString })
|
|
||||||
} else if (path is JsonPrimitive && path.isString) {
|
|
||||||
return NbtPrism(path.asString.split("."))
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "Prism($path)"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun access(root: NbtElement): Collection<NbtElement> {
|
|
||||||
var rootSet = mutableListOf(root)
|
|
||||||
var switch = mutableListOf<NbtElement>()
|
|
||||||
for (pathSegment in path) {
|
|
||||||
if (pathSegment == ".") continue
|
|
||||||
if (pathSegment != "*" && pathSegment.startsWith("*")) {
|
|
||||||
if (pathSegment == "*json") {
|
|
||||||
for (element in rootSet) {
|
|
||||||
val eString = element.asString().getOrNull() ?: continue
|
|
||||||
val element = Gson().fromJson(eString, JsonElement::class.java)
|
|
||||||
switch.add(JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, element))
|
|
||||||
}
|
|
||||||
} else if (pathSegment == "*base64") {
|
|
||||||
for (element in rootSet) {
|
|
||||||
val string = element.asString().getOrNull() ?: continue
|
|
||||||
switch.add(NbtString.of(Base64Util.decodeString(string)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (element in rootSet) {
|
|
||||||
if (element is NbtList) {
|
|
||||||
if (pathSegment == "*")
|
|
||||||
switch.addAll(element)
|
|
||||||
val index = pathSegment.toIntOrNull() ?: continue
|
|
||||||
if (index !in element.indices) continue
|
|
||||||
switch.add(element[index])
|
|
||||||
}
|
|
||||||
if (element is NbtCompound) {
|
|
||||||
if (pathSegment == "*")
|
|
||||||
element.keys.mapTo(switch) { element.get(it)!! }
|
|
||||||
switch.add(element.get(pathSegment) ?: continue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val temp = switch
|
|
||||||
switch = rootSet
|
|
||||||
rootSet = temp
|
|
||||||
switch.clear()
|
|
||||||
}
|
|
||||||
return rootSet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import net.minecraft.util.Identifier
|
|||||||
import moe.nea.firmament.features.texturepack.FirmamentModelPredicate
|
import moe.nea.firmament.features.texturepack.FirmamentModelPredicate
|
||||||
import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser
|
import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.mc.NbtPrism
|
||||||
|
|
||||||
data class GenericComponentPredicate<T>(
|
data class GenericComponentPredicate<T>(
|
||||||
val componentType: ComponentType<T>,
|
val componentType: ComponentType<T>,
|
||||||
|
|||||||
Reference in New Issue
Block a user