aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/features/debug
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/features/debug')
-rw-r--r--src/main/kotlin/features/debug/AnimatedClothingScanner.kt36
-rw-r--r--src/main/kotlin/features/debug/DebugLogger.kt9
-rw-r--r--src/main/kotlin/features/debug/DebugView.kt29
-rw-r--r--src/main/kotlin/features/debug/DeveloperFeatures.kt35
-rw-r--r--src/main/kotlin/features/debug/ExportedTestConstantMeta.kt8
-rw-r--r--src/main/kotlin/features/debug/MinorTrolling.kt10
-rw-r--r--src/main/kotlin/features/debug/PowerUserTools.kt174
-rw-r--r--src/main/kotlin/features/debug/SkinPreviews.kt91
-rw-r--r--src/main/kotlin/features/debug/SoundVisualizer.kt65
-rw-r--r--src/main/kotlin/features/debug/itemeditor/ExportRecipe.kt256
-rw-r--r--src/main/kotlin/features/debug/itemeditor/ItemExporter.kt250
-rw-r--r--src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt87
-rw-r--r--src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt318
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