diff options
Diffstat (limited to 'src/main/kotlin/features/debug')
| -rw-r--r-- | src/main/kotlin/features/debug/AnimatedClothingScanner.kt | 36 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/DebugLogger.kt | 9 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/DebugView.kt | 29 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/DeveloperFeatures.kt | 35 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/ExportedTestConstantMeta.kt | 8 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/MinorTrolling.kt | 10 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/PowerUserTools.kt | 174 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/SkinPreviews.kt | 91 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/SoundVisualizer.kt | 65 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt | 256 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/itemeditor/ItemExporter.kt | 250 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt | 87 | ||||
| -rw-r--r-- | src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt | 318 |
13 files changed, 1219 insertions, 149 deletions
diff --git a/src/main/kotlin/features/debug/AnimatedClothingScanner.kt b/src/main/kotlin/features/debug/AnimatedClothingScanner.kt index 9f9f135..dc77115 100644 --- a/src/main/kotlin/features/debug/AnimatedClothingScanner.kt +++ b/src/main/kotlin/features/debug/AnimatedClothingScanner.kt @@ -1,13 +1,13 @@ package moe.nea.firmament.features.debug -import net.minecraft.command.argument.RegistryKeyArgumentType -import net.minecraft.component.ComponentType -import net.minecraft.entity.Entity -import net.minecraft.entity.decoration.ArmorStandEntity -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NbtElement +import net.minecraft.commands.arguments.ResourceKeyArgument +import net.minecraft.core.component.DataComponentType +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.decoration.ArmorStand +import net.minecraft.world.item.ItemStack +import net.minecraft.nbt.Tag import net.minecraft.nbt.NbtOps -import net.minecraft.registry.RegistryKeys +import net.minecraft.core.registries.Registries import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.commands.get import moe.nea.firmament.commands.thenArgument @@ -27,11 +27,11 @@ object AnimatedClothingScanner { data class LensOfFashionTheft<T>( val prism: NbtPrism, - val component: ComponentType<T>, + val component: DataComponentType<T>, ) { - fun observe(itemStack: ItemStack): Collection<NbtElement> { + fun observe(itemStack: ItemStack): Collection<Tag> { val x = itemStack.get(component) ?: return listOf() - val nbt = component.codecOrThrow.encodeStart(NbtOps.INSTANCE, x).orThrow + val nbt = component.codecOrThrow().encodeStart(NbtOps.INSTANCE, x).orThrow return prism.access(nbt) } } @@ -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 { @@ -115,16 +115,16 @@ object AnimatedClothingScanner { ) ) val p = MC.player!! - val nearestPet = p.world.getEntitiesByClass( - ArmorStandEntity::class.java, - p.boundingBox.expand(10.0), + val nearestPet = p.level.getEntitiesOfClass( + ArmorStand::class.java, + p.boundingBox.inflate(10.0), { it.isMarker }) - .minBy { it.squaredDistanceTo(p) } + .minBy { it.distanceToSqr(p) } toggleObserve(nearestPet) } } thenExecute { - val ent = MC.instance.targetedEntity + val ent = MC.instance.crosshairPickEntity if (ent == null) { source.sendFeedback( tr( @@ -140,7 +140,7 @@ object AnimatedClothingScanner { thenLiteral("path") { thenArgument( "component", - RegistryKeyArgumentType.registryKey(RegistryKeys.DATA_COMPONENT_TYPE) + ResourceKeyArgument.key(Registries.DATA_COMPONENT_TYPE) ) { component -> thenArgument("path", NbtPrism.Argument) { path -> thenExecute { @@ -151,7 +151,7 @@ object AnimatedClothingScanner { source.sendFeedback( tr( "firmament.fitstealer.lensset", - "Analyzing path ${get(path)} for component ${get(component).value}" + "Analyzing path ${get(path)} for component ${get(component).location()}" ) ) } diff --git a/src/main/kotlin/features/debug/DebugLogger.kt b/src/main/kotlin/features/debug/DebugLogger.kt index 9115956..2c8ced0 100644 --- a/src/main/kotlin/features/debug/DebugLogger.kt +++ b/src/main/kotlin/features/debug/DebugLogger.kt @@ -1,9 +1,11 @@ package moe.nea.firmament.features.debug import kotlinx.serialization.serializer -import net.minecraft.text.Text +import net.minecraft.network.chat.Component import moe.nea.firmament.util.MC +import moe.nea.firmament.util.TestUtil import moe.nea.firmament.util.collections.InstanceList +import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.data.DataHolder class DebugLogger(val tag: String) { @@ -11,16 +13,17 @@ class DebugLogger(val tag: String) { val allInstances = InstanceList<DebugLogger>("DebugLogger") } + @Config object EnabledLogs : DataHolder<MutableSet<String>>(serializer(), "DebugLogs", ::mutableSetOf) init { allInstances.add(this) } - fun isEnabled() = DeveloperFeatures.isEnabled && EnabledLogs.data.contains(tag) + fun isEnabled() = TestUtil.isInTest || EnabledLogs.data.contains(tag) fun log(text: String) = log { text } fun log(text: () -> String) { if (!isEnabled()) return - MC.sendChat(Text.literal(text())) + MC.sendChat(Component.literal(text())) } } diff --git a/src/main/kotlin/features/debug/DebugView.kt b/src/main/kotlin/features/debug/DebugView.kt deleted file mode 100644 index ee54260..0000000 --- a/src/main/kotlin/features/debug/DebugView.kt +++ /dev/null @@ -1,29 +0,0 @@ - - -package moe.nea.firmament.features.debug - -import moe.nea.firmament.Firmament -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.util.TimeMark - -object DebugView : FirmamentFeature { - private data class StoredVariable<T>( - val obj: T, - val timer: TimeMark, - ) - - private val storedVariables: MutableMap<String, StoredVariable<*>> = sortedMapOf() - override val identifier: String - get() = "debug-view" - override val defaultEnabled: Boolean - get() = Firmament.DEBUG - - fun <T : Any?> showVariable(label: String, obj: T) { - synchronized(this) { - storedVariables[label] = StoredVariable(obj, TimeMark.now()) - } - } - -} diff --git a/src/main/kotlin/features/debug/DeveloperFeatures.kt b/src/main/kotlin/features/debug/DeveloperFeatures.kt index af1e92e..8638bb6 100644 --- a/src/main/kotlin/features/debug/DeveloperFeatures.kt +++ b/src/main/kotlin/features/debug/DeveloperFeatures.kt @@ -10,33 +10,31 @@ import org.spongepowered.asm.mixin.Mixin import kotlinx.serialization.json.encodeToStream import kotlin.io.path.absolute import kotlin.io.path.exists -import net.minecraft.client.MinecraftClient -import net.minecraft.text.Text +import net.minecraft.client.Minecraft +import net.minecraft.network.chat.Component import moe.nea.firmament.Firmament import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.DebugInstantiateEvent import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.init.MixinPlugin import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.asm.AsmAnnotationUtil +import moe.nea.firmament.util.data.Config +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.iterate -object DeveloperFeatures : FirmamentFeature { - override val identifier: String +object DeveloperFeatures { + val DEVELOPER_SUBCOMMAND: String = "dev" + val identifier: String get() = "developer" - override val config: TConfig - get() = TConfig - override val defaultEnabled: Boolean - get() = Firmament.DEBUG val gradleDir = Path.of(".").absolute() .iterate { it.parent } .find { it.resolve("settings.gradle.kts").exists() } + @Config object TConfig : ManagedConfig("developer", Category.DEV) { val autoRebuildResources by toggle("auto-rebuild") { false } } @@ -94,24 +92,27 @@ object DeveloperFeatures : FirmamentFeature { } @JvmStatic - fun hookOnBeforeResourceReload(client: MinecraftClient): CompletableFuture<Void> { - val reloadFuture = if (TConfig.autoRebuildResources && isEnabled && gradleDir != null) { + fun hookOnBeforeResourceReload(client: Minecraft): CompletableFuture<Void> { + val reloadFuture = if (TConfig.autoRebuildResources && Firmament.DEBUG && gradleDir != null) { val builder = ProcessBuilder("./gradlew", ":processResources") builder.directory(gradleDir.toFile()) builder.inheritIO() val process = builder.start() - MC.sendChat(Text.translatable("firmament.dev.resourcerebuild.start")) + MC.sendChat(Component.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( + Component.translatableEscape( + "firmament.dev.resourcerebuild.done", + startTime.passedTime() + ) + ) Unit } } else { CompletableFuture.completedFuture(Unit) } - return reloadFuture.thenCompose { client.reloadResources() } + return reloadFuture.thenCompose { client.reloadResourcePacks() } } } diff --git a/src/main/kotlin/features/debug/ExportedTestConstantMeta.kt b/src/main/kotlin/features/debug/ExportedTestConstantMeta.kt index a817dd6..a2b42fd 100644 --- a/src/main/kotlin/features/debug/ExportedTestConstantMeta.kt +++ b/src/main/kotlin/features/debug/ExportedTestConstantMeta.kt @@ -3,17 +3,25 @@ package moe.nea.firmament.features.debug import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import java.util.Optional +import net.minecraft.SharedConstants +import moe.nea.firmament.Firmament data class ExportedTestConstantMeta( val dataVersion: Int, val modVersion: Optional<String>, ) { companion object { + val current = ExportedTestConstantMeta( + SharedConstants.getCurrentVersion().dataVersion().version, + Optional.of("Firmament ${Firmament.version.friendlyString}") + ) + val CODEC: Codec<ExportedTestConstantMeta> = RecordCodecBuilder.create { it.group( Codec.INT.fieldOf("dataVersion").forGetter(ExportedTestConstantMeta::dataVersion), Codec.STRING.optionalFieldOf("modVersion").forGetter(ExportedTestConstantMeta::modVersion), ).apply(it, ::ExportedTestConstantMeta) } + val SOURCE_CODEC = CODEC.fieldOf("source").codec() } } diff --git a/src/main/kotlin/features/debug/MinorTrolling.kt b/src/main/kotlin/features/debug/MinorTrolling.kt index 32035a6..7936521 100644 --- a/src/main/kotlin/features/debug/MinorTrolling.kt +++ b/src/main/kotlin/features/debug/MinorTrolling.kt @@ -2,15 +2,13 @@ package moe.nea.firmament.features.debug -import net.minecraft.text.Text +import net.minecraft.network.chat.Component import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ModifyChatEvent -import moe.nea.firmament.features.FirmamentFeature - // In memorian Dulkir -object MinorTrolling : FirmamentFeature { - override val identifier: String +object MinorTrolling { + val identifier: String get() = "minor-trolling" val trollers = listOf("nea89o", "lrg89") @@ -22,6 +20,6 @@ object MinorTrolling : FirmamentFeature { val (_, name, text) = m.groupValues if (name !in trollers) return if (!text.startsWith("c:")) return - it.replaceWith = Text.literal(text.substring(2).replace("&", "§")) + it.replaceWith = Component.literal(text.substring(2).replace("&", "§")) } } diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt index 893b176..145ea35 100644 --- a/src/main/kotlin/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/features/debug/PowerUserTools.kt @@ -2,50 +2,55 @@ package moe.nea.firmament.features.debug import com.mojang.serialization.JsonOps import kotlin.jvm.optionals.getOrNull -import net.minecraft.block.SkullBlock -import net.minecraft.block.entity.SkullBlockEntity -import net.minecraft.component.DataComponentTypes -import net.minecraft.component.type.ProfileComponent -import net.minecraft.entity.Entity -import net.minecraft.entity.LivingEntity -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.nbt.NbtList +import net.minecraft.world.level.block.SkullBlock +import net.minecraft.world.level.block.entity.SkullBlockEntity +import net.minecraft.core.component.DataComponents +import net.minecraft.world.item.component.ResolvableProfile +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.nbt.ListTag import net.minecraft.nbt.NbtOps -import net.minecraft.predicate.NbtPredicate -import net.minecraft.text.Text -import net.minecraft.text.TextCodecs -import net.minecraft.util.Identifier -import net.minecraft.util.Nameable -import net.minecraft.util.hit.BlockHitResult -import net.minecraft.util.hit.EntityHitResult -import net.minecraft.util.hit.HitResult +import net.minecraft.advancements.critereon.NbtPredicate +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.ComponentSerialization +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.Nameable +import net.minecraft.world.phys.BlockHitResult +import net.minecraft.world.phys.EntityHitResult +import net.minecraft.world.phys.HitResult import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.CustomItemModelEvent import moe.nea.firmament.events.HandledScreenKeyPressedEvent import moe.nea.firmament.events.ItemTooltipEvent import moe.nea.firmament.events.ScreenChangeEvent +import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.events.TickEvent import moe.nea.firmament.events.WorldKeyboardEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.mixins.accessor.AccessorHandledScreen import moe.nea.firmament.util.ClipboardUtils import moe.nea.firmament.util.MC +import moe.nea.firmament.util.data.Config +import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.focusedItemStack +import moe.nea.firmament.util.grey import moe.nea.firmament.util.mc.IntrospectableItemModelManager import moe.nea.firmament.util.mc.SNbtFormatter import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString import moe.nea.firmament.util.mc.displayNameAccordingToNbt import moe.nea.firmament.util.mc.iterableArmorItems import moe.nea.firmament.util.mc.loreAccordingToNbt +import moe.nea.firmament.util.mc.unsafeNbt import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.tr -object PowerUserTools : FirmamentFeature { - override val identifier: String +object PowerUserTools { + val identifier: String get() = "power-user" + @Config object TConfig : ManagedConfig(identifier, Category.DEV) { val showItemIds by toggle("show-item-id") { false } val copyItemId by keyBindingWithDefaultUnbound("copy-item-id") @@ -56,22 +61,25 @@ object PowerUserTools : FirmamentFeature { val copyEntityData by keyBindingWithDefaultUnbound("entity-data") val copyItemStack by keyBindingWithDefaultUnbound("copy-item-stack") val copyTitle by keyBindingWithDefaultUnbound("copy-title") + val exportItemStackToRepo by keyBindingWithDefaultUnbound("export-item-stack") + val exportUIRecipes by keyBindingWithDefaultUnbound("export-recipe") + val exportNpcLocation by keyBindingWithDefaultUnbound("export-npc-location") + val highlightNonOverlayItems by toggle("highlight-non-overlay") { false } + val dontHighlightSemicolonItems by toggle("dont-highlight-semicolon-items") { false } + val showSlotNumbers by keyBindingWithDefaultUnbound("slot-numbers") + val autoCopyAnimatedSkins by toggle("copy-animated-skins") { false } } - override val config - get() = TConfig - - var lastCopiedStack: Pair<ItemStack, Text>? = null + var lastCopiedStack: Pair<ItemStack, Component>? = null set(value) { field = value - if (value != null) lastCopiedStackViewTime = true + if (value != null) lastCopiedStackViewTime = 2 } - var lastCopiedStackViewTime = false + var lastCopiedStackViewTime = 0 @Subscribe fun resetLastCopiedStack(event: TickEvent) { - if (!lastCopiedStackViewTime) lastCopiedStack = null - lastCopiedStackViewTime = false + if (lastCopiedStackViewTime-- < 0) lastCopiedStack = null } @Subscribe @@ -79,44 +87,58 @@ object PowerUserTools : FirmamentFeature { lastCopiedStack = null } - fun debugFormat(itemStack: ItemStack): Text { - return Text.literal(itemStack.skyBlockId?.toString() ?: itemStack.toString()) + fun debugFormat(itemStack: ItemStack): Component { + return Component.literal(itemStack.skyBlockId?.toString() ?: itemStack.toString()) + } + + @Subscribe + fun onRender(event: SlotRenderEvents.After) { + if (TConfig.showSlotNumbers.isPressed()) { + event.context.drawString( + MC.font, + event.slot.index.toString(), event.slot.x, event.slot.y, 0xFF00FF00.toInt(), true + ) + event.context.drawString( + MC.font, + event.slot.containerSlot.toString(), event.slot.x, event.slot.y + MC.font.lineHeight, 0xFFFF0000.toInt(), true + ) + } } @Subscribe fun onEntityInfo(event: WorldKeyboardEvent) { if (!event.matches(TConfig.copyEntityData)) return - val target = (MC.instance.crosshairTarget as? EntityHitResult)?.entity + val target = (MC.instance.hitResult as? EntityHitResult)?.entity if (target == null) { - MC.sendChat(Text.translatable("firmament.poweruser.entity.fail")) + MC.sendChat(Component.translatable("firmament.poweruser.entity.fail")) return } showEntity(target) } fun showEntity(target: Entity) { - val nbt = NbtPredicate.entityToNbt(target) + val nbt = NbtPredicate.getEntityTagToCompare(target) nbt.remove("Inventory") - nbt.put("StyledName", TextCodecs.CODEC.encodeStart(NbtOps.INSTANCE, target.styledDisplayName).orThrow) + nbt.put("StyledName", ComponentSerialization.CODEC.encodeStart(NbtOps.INSTANCE, target.feedbackDisplayName).orThrow) println(SNbtFormatter.prettify(nbt)) ClipboardUtils.setTextContent(SNbtFormatter.prettify(nbt)) - MC.sendChat(Text.translatable("firmament.poweruser.entity.type", target.type)) - MC.sendChat(Text.translatable("firmament.poweruser.entity.name", target.name)) - MC.sendChat(Text.stringifiedTranslatable("firmament.poweruser.entity.position", target.pos)) + MC.sendChat(Component.translatable("firmament.poweruser.entity.type", target.type)) + MC.sendChat(Component.translatable("firmament.poweruser.entity.name", target.name)) + MC.sendChat(Component.translatableEscape("firmament.poweruser.entity.position", target.position)) if (target is LivingEntity) { - MC.sendChat(Text.translatable("firmament.poweruser.entity.armor")) + MC.sendChat(Component.translatable("firmament.poweruser.entity.armor")) for ((slot, armorItem) in target.iterableArmorItems) { - MC.sendChat(Text.translatable("firmament.poweruser.entity.armor.item", debugFormat(armorItem))) + MC.sendChat(Component.translatable("firmament.poweruser.entity.armor.item", debugFormat(armorItem))) } } - MC.sendChat(Text.stringifiedTranslatable("firmament.poweruser.entity.passengers", target.passengerList.size)) - target.passengerList.forEach { + MC.sendChat(Component.translatableEscape("firmament.poweruser.entity.passengers", target.passengers.size)) + target.passengers.forEach { showEntity(it) } } // TODO: leak this through some other way, maybe. - lateinit var getSkullId: (profile: ProfileComponent) -> Identifier? + lateinit var getSkullId: (profile: ResolvableProfile) -> ResourceLocation? @Subscribe fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) { @@ -125,71 +147,71 @@ object PowerUserTools : FirmamentFeature { if (it.matches(TConfig.copyItemId)) { val sbId = item.skyBlockId if (sbId == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail")) + lastCopiedStack = Pair(item, Component.translatable("firmament.tooltip.copied.skyblockid.fail")) return } ClipboardUtils.setTextContent(sbId.neuItem) lastCopiedStack = - Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem)) + Pair(item, Component.translatableEscape("firmament.tooltip.copied.skyblockid", sbId.neuItem)) } else if (it.matches(TConfig.copyTexturePackId)) { val model = CustomItemModelEvent.getModelIdentifier0(item, object : IntrospectableItemModelManager { - override fun hasModel_firmament(identifier: Identifier): Boolean { + override fun hasModel_firmament(identifier: ResourceLocation): Boolean { return true } }).getOrNull() // TODO: remove global texture overrides, maybe if (model == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail")) + lastCopiedStack = Pair(item, Component.translatable("firmament.tooltip.copied.modelid.fail")) return } ClipboardUtils.setTextContent(model.toString()) lastCopiedStack = - Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString())) + Pair(item, Component.translatableEscape("firmament.tooltip.copied.modelid", model.toString())) } else if (it.matches(TConfig.copyNbtData)) { // TODO: copy full nbt - val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toPrettyString() ?: "<empty>" + val nbt = item.get(DataComponents.CUSTOM_DATA)?.unsafeNbt?.toPrettyString() ?: "<empty>" ClipboardUtils.setTextContent(nbt) - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt")) + lastCopiedStack = Pair(item, Component.translatable("firmament.tooltip.copied.nbt")) } else if (it.matches(TConfig.copyLoreData)) { val list = mutableListOf(item.displayNameAccordingToNbt) list.addAll(item.loreAccordingToNbt) ClipboardUtils.setTextContent(list.joinToString("\n") { - TextCodecs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().getOrNull().toString() + ComponentSerialization.CODEC.encodeStart(JsonOps.INSTANCE, it).result().getOrNull().toString() }) - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.lore")) + lastCopiedStack = Pair(item, Component.translatable("firmament.tooltip.copied.lore")) } else if (it.matches(TConfig.copySkullTexture)) { if (item.item != Items.PLAYER_HEAD) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull")) + lastCopiedStack = Pair(item, Component.translatable("firmament.tooltip.copied.skull-id.fail.no-skull")) return } - val profile = item.get(DataComponentTypes.PROFILE) + val profile = item.get(DataComponents.PROFILE) if (profile == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile")) + lastCopiedStack = Pair(item, Component.translatable("firmament.tooltip.copied.skull-id.fail.no-profile")) return } val skullTexture = getSkullId(profile) if (skullTexture == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture")) + lastCopiedStack = Pair(item, Component.translatable("firmament.tooltip.copied.skull-id.fail.no-texture")) return } ClipboardUtils.setTextContent(skullTexture.toString()) lastCopiedStack = - Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString())) + Pair(item, Component.translatableEscape("firmament.tooltip.copied.skull-id", skullTexture.toString())) println("Copied skull id: $skullTexture") } else if (it.matches(TConfig.copyItemStack)) { val nbt = ItemStack.CODEC - .encodeStart(MC.currentOrDefaultRegistries.getOps(NbtOps.INSTANCE), item) + .encodeStart(MC.currentOrDefaultRegistries.createSerializationContext(NbtOps.INSTANCE), item) .orThrow ClipboardUtils.setTextContent(nbt.toPrettyString()) - lastCopiedStack = Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.stack")) - } else if (it.matches(TConfig.copyTitle)) { - val allTitles = NbtList() + lastCopiedStack = Pair(item, Component.translatableEscape("firmament.tooltip.copied.stack")) + } else if (it.matches(TConfig.copyTitle) && it.screen is AbstractContainerScreen<*>) { + val allTitles = ListTag() val inventoryNames = - it.screen.screenHandler.slots - .mapNotNullTo(mutableSetOf()) { it.inventory } + it.screen.menu.slots + .mapNotNullTo(mutableSetOf()) { it.container } .filterIsInstance<Nameable>() .map { it.name } for (it in listOf(it.screen.title) + inventoryNames) { - allTitles.add(TextCodecs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().getOrNull()!!) + allTitles.add(ComponentSerialization.CODEC.encodeStart(NbtOps.INSTANCE, it).result().getOrNull()!!) } ClipboardUtils.setTextContent(allTitles.toPrettyString()) MC.sendChat(tr("firmament.power-user.title.copied", "Copied screen and inventory titles")) @@ -200,23 +222,23 @@ object PowerUserTools : FirmamentFeature { fun onCopyWorldInfo(it: WorldKeyboardEvent) { if (it.matches(TConfig.copySkullTexture)) { val p = MC.camera ?: return - val blockHit = p.raycast(20.0, 0.0f, false) ?: return + val blockHit = p.pick(20.0, 0.0f, false) ?: return if (blockHit.type != HitResult.Type.BLOCK || blockHit !is BlockHitResult) { - MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + MC.sendChat(Component.translatable("firmament.tooltip.copied.skull.fail")) return } - val blockAt = p.world.getBlockState(blockHit.blockPos)?.block - val entity = p.world.getBlockEntity(blockHit.blockPos) - if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.owner == null) { - MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + val blockAt = p.level.getBlockState(blockHit.blockPos)?.block + val entity = p.level.getBlockEntity(blockHit.blockPos) + if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.ownerProfile == null) { + MC.sendChat(Component.translatable("firmament.tooltip.copied.skull.fail")) return } - val id = getSkullId(entity.owner!!) + val id = getSkullId(entity.ownerProfile!!) if (id == null) { - MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + MC.sendChat(Component.translatable("firmament.tooltip.copied.skull.fail")) } else { ClipboardUtils.setTextContent(id.toString()) - MC.sendChat(Text.stringifiedTranslatable("firmament.tooltip.copied.skull", id.toString())) + MC.sendChat(Component.translatableEscape("firmament.tooltip.copied.skull", id.toString())) } } } @@ -225,14 +247,14 @@ object PowerUserTools : FirmamentFeature { fun addItemId(it: ItemTooltipEvent) { if (TConfig.showItemIds) { val id = it.stack.skyBlockId ?: return - it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem)) + it.lines.add(Component.translatableEscape("firmament.tooltip.skyblockid", id.neuItem).grey()) } val (item, text) = lastCopiedStack ?: return - if (!ItemStack.areEqual(item, it.stack)) { + if (!ItemStack.matches(item, it.stack)) { lastCopiedStack = null return } - lastCopiedStackViewTime = true + lastCopiedStackViewTime = 0 it.lines.add(text) } diff --git a/src/main/kotlin/features/debug/SkinPreviews.kt b/src/main/kotlin/features/debug/SkinPreviews.kt new file mode 100644 index 0000000..56c63db --- /dev/null +++ b/src/main/kotlin/features/debug/SkinPreviews.kt @@ -0,0 +1,91 @@ +package moe.nea.firmament.features.debug + +import com.mojang.authlib.GameProfile +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import kotlin.time.Duration.Companion.seconds +import net.minecraft.core.component.DataComponents +import net.minecraft.world.item.component.ResolvableProfile +import net.minecraft.world.entity.EquipmentSlot +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.phys.Vec3 +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.EntityUpdateEvent +import moe.nea.firmament.events.IsSlotProtectedEvent +import moe.nea.firmament.util.ClipboardUtils +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.extraAttributes +import moe.nea.firmament.util.json.toJsonArray +import moe.nea.firmament.util.math.GChainReconciliation.shortenCycle +import moe.nea.firmament.util.mc.displayNameAccordingToNbt +import moe.nea.firmament.util.mc.loreAccordingToNbt +import moe.nea.firmament.util.rawSkyBlockId +import moe.nea.firmament.util.toTicks +import moe.nea.firmament.util.tr + + +object SkinPreviews { + + // TODO: add pet support + @Subscribe + fun onEntityUpdate(event: EntityUpdateEvent) { + if (!isRecording) return + if (event.entity.position != pos) + return + val entity = event.entity as? LivingEntity ?: return + val stack = entity.getItemBySlot(EquipmentSlot.HEAD) ?: return + val profile = stack.get(DataComponents.PROFILE)?.partialProfile() ?: return + if (profile == animation.lastOrNull()) return + animation.add(profile) + val shortened = animation.shortenCycle() + if (shortened.size <= (animation.size / 2).coerceAtLeast(1) && lastDiscard.passedTime() > 2.seconds) { + val tickEstimation = (lastDiscard.passedTime() / animation.size).toTicks() + val skinName = if (skinColor != null) "${skinId}_${skinColor?.replace(" ", "_")?.uppercase()}" else skinId!! + val json = + buildJsonObject { + put("ticks", tickEstimation) + put( + "textures", + shortened.map { + it.id.toString() + ":" + it.properties()["textures"].first().value() + }.toJsonArray() + ) + } + MC.sendChat( + tr( + "firmament.dev.skinpreviews.done", + "Observed a total of ${animation.size} elements, which could be shortened to a cycle of ${shortened.size}. Copying JSON array. Estimated ticks per frame: $tickEstimation." + ) + ) + isRecording = false + ClipboardUtils.setTextContent(JsonPrimitive(skinName).toString() + ":" + json.toString()) + } + } + + var animation = mutableListOf<GameProfile>() + var pos = Vec3(-1.0, 72.0, -101.25) + var isRecording = false + var skinColor: String? = null + var skinId: String? = null + var lastDiscard = TimeMark.farPast() + + @Subscribe + fun onActivate(event: IsSlotProtectedEvent) { + if (!PowerUserTools.TConfig.autoCopyAnimatedSkins) return + val lastLine = event.itemStack.loreAccordingToNbt.lastOrNull()?.string + if (lastLine != "Right-click to preview!" && lastLine != "Click to preview!") return + lastDiscard = TimeMark.now() + val stackName = event.itemStack.displayNameAccordingToNbt.string + if (stackName == "FIRE SALE!") { + skinColor = null + skinId = event.itemStack.rawSkyBlockId + } else { + skinColor = stackName + } + animation.clear() + isRecording = true + MC.sendChat(tr("firmament.dev.skinpreviews.start", "Starting to observe items")) + } +} diff --git a/src/main/kotlin/features/debug/SoundVisualizer.kt b/src/main/kotlin/features/debug/SoundVisualizer.kt new file mode 100644 index 0000000..37b248a --- /dev/null +++ b/src/main/kotlin/features/debug/SoundVisualizer.kt @@ -0,0 +1,65 @@ +package moe.nea.firmament.features.debug + +import net.minecraft.network.chat.Component +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.SoundReceiveEvent +import moe.nea.firmament.events.WorldReadyEvent +import moe.nea.firmament.events.WorldRenderLastEvent +import moe.nea.firmament.util.red +import moe.nea.firmament.util.render.RenderInWorldContext + +object SoundVisualizer { + + var showSounds = false + + var sounds = mutableListOf<SoundReceiveEvent>() + + + @Subscribe + fun onSubCommand(event: CommandEvent.SubCommand) { + event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) { + thenLiteral("sounds") { + thenExecute { + showSounds = !showSounds + if (!showSounds) { + sounds.clear() + } + } + } + } + } + + @Subscribe + fun onWorldSwap(event: WorldReadyEvent) { + sounds.clear() + } + + @Subscribe + fun onRender(event: WorldRenderLastEvent) { + RenderInWorldContext.renderInWorld(event) { + sounds.forEach { event -> + withFacingThePlayer(event.position) { + text( + Component.literal(event.sound.value().location.toString()).also { + if (event.cancelled) + it.red() + }, + verticalAlign = RenderInWorldContext.VerticalAlign.CENTER, + ) + } + } + } + } + + @Subscribe + fun onSoundReceive(event: SoundReceiveEvent) { + if (!showSounds) return + if (sounds.size > 1000) { + sounds.subList(0, 200).clear() + } + sounds.add(event) + } +} diff --git a/src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt b/src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt new file mode 100644 index 0000000..d12d667 --- /dev/null +++ b/src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt @@ -0,0 +1,256 @@ +package moe.nea.firmament.features.debug.itemeditor + +import kotlinx.coroutines.launch +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import net.minecraft.client.player.AbstractClientPlayer +import net.minecraft.world.entity.decoration.ArmorStand +import net.minecraft.core.ClientAsset +import moe.nea.firmament.Firmament +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.eve |
