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/ExportedTestConstantMeta.kt8
-rw-r--r--src/main/kotlin/features/debug/itemeditor/ItemExporter.kt265
-rw-r--r--src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt240
3 files changed, 281 insertions, 232 deletions
diff --git a/src/main/kotlin/features/debug/ExportedTestConstantMeta.kt b/src/main/kotlin/features/debug/ExportedTestConstantMeta.kt
index a817dd6..f0250dc 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.getGameVersion().saveVersion.id,
+ 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/itemeditor/ItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
index db2f36f..5cf1c85 100644
--- a/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
+++ b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
@@ -1,252 +1,53 @@
package moe.nea.firmament.features.debug.itemeditor
-import kotlinx.serialization.json.JsonArray
-import kotlinx.serialization.json.JsonElement
-import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
-import kotlinx.serialization.json.put
-import kotlin.concurrent.thread
import kotlin.io.path.createParentDirectories
import kotlin.io.path.relativeTo
import kotlin.io.path.writeText
-import net.minecraft.component.DataComponentTypes
import net.minecraft.item.ItemStack
-import net.minecraft.nbt.NbtCompound
-import net.minecraft.nbt.NbtInt
-import net.minecraft.nbt.NbtString
-import net.minecraft.text.Text
-import net.minecraft.util.Unit
+import net.minecraft.nbt.NbtOps
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
-import moe.nea.firmament.events.ClientStartedEvent
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
+import moe.nea.firmament.features.debug.ExportedTestConstantMeta
import moe.nea.firmament.features.debug.PowerUserTools
import moe.nea.firmament.repo.RepoDownloadManager
-import moe.nea.firmament.util.HypixelPetInfo
-import moe.nea.firmament.util.LegacyTagWriter.Companion.toLegacyString
-import moe.nea.firmament.util.StringUtil.words
-import moe.nea.firmament.util.directLiteralStringContent
-import moe.nea.firmament.util.extraAttributes
import moe.nea.firmament.util.focusedItemStack
-import moe.nea.firmament.util.getLegacyFormatString
-import moe.nea.firmament.util.json.toJsonArray
-import moe.nea.firmament.util.mc.displayNameAccordingToNbt
-import moe.nea.firmament.util.mc.loreAccordingToNbt
-import moe.nea.firmament.util.mc.toNbtList
-import moe.nea.firmament.util.skyBlockId
-import moe.nea.firmament.util.skyblock.Rarity
+import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString
import moe.nea.firmament.util.tr
-import moe.nea.firmament.util.transformEachRecursively
-import moe.nea.firmament.util.unformattedString
-class ItemExporter(var itemStack: ItemStack) {
- var lore = itemStack.loreAccordingToNbt
- var name = itemStack.displayNameAccordingToNbt
- val extraAttribs = itemStack.extraAttributes.copy()
- val legacyNbt = NbtCompound()
- val warnings = mutableListOf<String>()
-
- fun preprocess() {
- // TODO: split up preprocess steps into preprocess actions that can be toggled in a ui
- extraAttribs.remove("timestamp")
- extraAttribs.remove("uuid")
- extraAttribs.remove("modifier")
- extraAttribs.getString("petInfo").ifPresent { petInfoJson ->
- var petInfo = Firmament.json.decodeFromString<HypixelPetInfo>(petInfoJson)
- petInfo = petInfo.copy(candyUsed = 0, heldItem = null, exp = 0.0, active = null, uuid = null)
- extraAttribs.putString("petInfo", Firmament.tightJson.encodeToString(petInfo))
- }
- itemStack.skyBlockId?.let {
- extraAttribs.putString("id", it.neuItem)
- }
- trimLore()
- }
-
- fun trimLore() {
- val rarityIdx = lore.indexOfLast {
- val firstWordInLine = it.unformattedString.words().filter { it.length > 2 }.firstOrNull()
- firstWordInLine?.let(Rarity::fromString) != null
- }
- if (rarityIdx >= 0) {
- lore = lore.subList(0, rarityIdx + 1)
- }
- deleteLineUntilNextSpace { it.startsWith("Held Item: ") }
- deleteLineUntilNextSpace { it.startsWith("Progress to Level ") }
- deleteLineUntilNextSpace { it.startsWith("MAX LEVEL") }
- collapseWhitespaces()
-
- name = name.transformEachRecursively {
- var string = it.directLiteralStringContent ?: return@transformEachRecursively it
- string = string.replace("Lvl \\d+".toRegex(), "Lvl {LVL}")
- Text.literal(string).setStyle(it.style)
- }
- }
-
- fun collapseWhitespaces() {
- lore = (listOf(null as Text?) + lore).zipWithNext()
- .filter { !it.first?.unformattedString.isNullOrBlank() || !it.second?.unformattedString.isNullOrBlank() }
- .map { it.second!! }
- }
-
- fun deleteLineUntilNextSpace(search: (String) -> Boolean) {
- val idx = lore.indexOfFirst { search(it.unformattedString) }
- if (idx < 0) return
- val l = lore.toMutableList()
- val p = l.subList(idx, l.size)
- val nextBlank = p.indexOfFirst { it.unformattedString.isEmpty() }
- if (nextBlank < 0)
- p.clear()
- else
- p.subList(0, nextBlank).clear()
- lore = l
- }
-
- fun processNbt() {
- // TODO: calculate hideflags
- legacyNbt.put("HideFlags", NbtInt.of(254))
- copyUnbreakable()
- copyItemModel()
- copyExtraAttributes()
- copyLegacySkullNbt()
- copyDisplay()
- copyEnchantments()
- copyEnchantGlint()
- // TODO: copyDisplay
- }
-
- private fun copyItemModel() {
- val itemModel = itemStack.get(DataComponentTypes.ITEM_MODEL) ?: return
- legacyNbt.put("ItemModel", NbtString.of(itemModel.toString()))
- }
-
- private fun copyDisplay() {
- legacyNbt.put("display", NbtCompound().apply {
- put("Lore", lore.map { NbtString.of(it.getLegacyFormatString(trimmed = true)) }.toNbtList())
- putString("Name", name.getLegacyFormatString(trimmed = true))
- })
- }
-
- fun exportJson(): JsonElement {
- preprocess()
- processNbt()
- return buildJsonObject {
- val (itemId, damage) = legacyifyItemStack()
- put("itemid", itemId)
- put("displayname", name.getLegacyFormatString(trimmed = true))
- put("nbttag", legacyNbt.toLegacyString())
- put("damage", damage)
- put("lore", lore.map { it.getLegacyFormatString(trimmed = true) }.toJsonArray())
- val sbId = itemStack.skyBlockId
- if (sbId == null)
- warnings.add("Could not find skyblock id")
- put("internalname", sbId?.neuItem)
- put("clickcommand", "")
- put("crafttext", "")
- put("modver", "Firmament ${Firmament.version.friendlyString}")
- put("infoType", "")
- put("info", JsonArray(listOf()))
- }
-
- }
-
- companion object {
- @Subscribe
- fun load(event: ClientStartedEvent) {
- thread(start = true, name = "ItemExporter Meta Load Thread") {
- LegacyItemData.itemLut
- }
- }
-
- @Subscribe
- fun onKeyBind(event: HandledScreenKeyPressedEvent) {
- if (event.matches(PowerUserTools.TConfig.exportItemStackToRepo)) {
- val itemStack = event.screen.focusedItemStack ?: return
- val exporter = ItemExporter(itemStack)
- val json = exporter.exportJson()
- val jsonFormatted = Firmament.twoSpaceJson.encodeToString(json)
- val itemFile = RepoDownloadManager.repoSavedLocation.resolve("items")
- .resolve("${json.jsonObject["internalname"]!!.jsonPrimitive.content}.json")
- itemFile.createParentDirectories()
- itemFile.writeText(jsonFormatted)
- PowerUserTools.lastCopiedStack = Pair(
- itemStack,
- tr(
- "firmament.repoexport.success",
- "Exported item to ${itemFile.relativeTo(RepoDownloadManager.repoSavedLocation)}${
- exporter.warnings.joinToString(
- ""
- ) { "\nWarning: $it" }
- }"
- )
+object ItemExporter {
+
+
+ @Subscribe
+ fun onKeyBind(event: HandledScreenKeyPressedEvent) {
+ if (event.matches(PowerUserTools.TConfig.exportItemStackToRepo)) {
+ val itemStack = event.screen.focusedItemStack ?: return
+ val exporter = LegacyItemExporter.createExporter(itemStack)
+ val json = exporter.exportJson()
+ val jsonFormatted = Firmament.twoSpaceJson.encodeToString(json)
+ val fileName = json.jsonObject["internalname"]!!.jsonPrimitive.content
+ val itemFile = RepoDownloadManager.repoSavedLocation.resolve("items").resolve("${fileName}.json")
+ itemFile.createParentDirectories()
+ itemFile.writeText(jsonFormatted)
+ val overlayFile = RepoDownloadManager.repoSavedLocation.resolve("itemsOverlay")
+ .resolve(ExportedTestConstantMeta.current.dataVersion.toString())
+ .resolve("${fileName}.snbt")
+ overlayFile.createParentDirectories()
+ overlayFile.writeText(exporter.exportModernSnbt().toPrettyString())
+
+ PowerUserTools.lastCopiedStack = Pair(
+ itemStack,
+ tr(
+ "firmament.repoexport.success",
+ "Exported item to ${itemFile.relativeTo(RepoDownloadManager.repoSavedLocation)}${
+ exporter.warnings.joinToString(
+ ""
+ ) { "\nWarning: $it" }
+ }"
)
- }
- }
- }
-
- fun copyEnchantGlint() {
- if (itemStack.get(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE) == true) {
- val ench = legacyNbt.getListOrEmpty("ench")
- legacyNbt.put("ench", ench)
- }
- }
-
- private fun copyUnbreakable() {
- if (itemStack.get(DataComponentTypes.UNBREAKABLE) == Unit.INSTANCE) {
- legacyNbt.putBoolean("Unbreakable", true)
+ )
}
}
-
- fun copyEnchantments() {
- val enchantments = itemStack.get(DataComponentTypes.ENCHANTMENTS)?.takeIf { !it.isEmpty } ?: return
- val enchTag = legacyNbt.getListOrEmpty("ench")
- legacyNbt.put("ench", enchTag)
- enchantments.enchantmentEntries.forEach { entry ->
- val id = entry.key.key.get().value
- val legacyId = LegacyItemData.enchantmentLut[id]
- if (legacyId == null) {
- warnings.add("Could not find legacy enchantment id for ${id}")
- return@forEach
- }
- enchTag.add(NbtCompound().apply {
- putShort("lvl", entry.intValue.toShort())
- putShort(
- "id",
- legacyId.id.toShort()
- )
- })
- }
- }
-
- fun copyExtraAttributes() {
- legacyNbt.put("ExtraAttributes", extraAttribs)
- }
-
- fun copyLegacySkullNbt() {
- val profile = itemStack.get(DataComponentTypes.PROFILE) ?: return
- legacyNbt.put("SkullOwner", NbtCompound().apply {
- profile.id.ifPresent {
- putString("Id", it.toString())
- }
- putBoolean("hypixelPopulated", true)
- put("Properties", NbtCompound().apply {
- profile.properties().forEach { prop, value ->
- val list = getListOrEmpty(prop)
- put(prop, list)
- list.add(NbtCompound().apply {
- value.signature?.let {
- putString("Signature", it)
- }
- putString("Value", value.value)
- putString("Name", value.name)
- })
- }
- })
- })
- }
-
- fun legacyifyItemStack(): LegacyItemData.LegacyItemType {
- // TODO: add a default here
- return LegacyItemData.itemLut[itemStack.item]!!
- }
}
diff --git a/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
new file mode 100644
index 0000000..f9d57d4
--- /dev/null
+++ b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
@@ -0,0 +1,240 @@
+package moe.nea.firmament.features.debug.itemeditor
+
+import kotlinx.serialization.json.JsonArray
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.put
+import kotlin.concurrent.thread
+import net.minecraft.component.DataComponentTypes
+import net.minecraft.item.ItemStack
+import net.minecraft.nbt.NbtCompound
+import net.minecraft.nbt.NbtElement
+import net.minecraft.nbt.NbtInt
+import net.minecraft.nbt.NbtOps
+import net.minecraft.nbt.NbtString
+import net.minecraft.text.Text
+import net.minecraft.util.Unit
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.events.ClientStartedEvent
+import moe.nea.firmament.features.debug.ExportedTestConstantMeta
+import moe.nea.firmament.util.HypixelPetInfo
+import moe.nea.firmament.util.LegacyTagWriter.Companion.toLegacyString
+import moe.nea.firmament.util.StringUtil.words
+import moe.nea.firmament.util.directLiteralStringContent
+import moe.nea.firmament.util.extraAttributes
+import moe.nea.firmament.util.getLegacyFormatString
+import moe.nea.firmament.util.json.toJsonArray
+import moe.nea.firmament.util.mc.displayNameAccordingToNbt
+import moe.nea.firmament.util.mc.loreAccordingToNbt
+import moe.nea.firmament.util.mc.toNbtList
+import moe.nea.firmament.util.skyBlockId
+import moe.nea.firmament.util.skyblock.Rarity
+import moe.nea.firmament.util.transformEachRecursively
+import moe.nea.firmament.util.unformattedString
+
+class LegacyItemExporter private constructor(var itemStack: ItemStack) {
+ var lore = itemStack.loreAccordingToNbt
+ var name = itemStack.displayNameAccordingToNbt
+ val extraAttribs = itemStack.extraAttributes.copy()
+ val legacyNbt = NbtCompound()
+ val warnings = mutableListOf<String>()
+
+ // TODO: check if lore contains non 1.8.9 able hex codes and emit lore in overlay files if so
+
+ fun preprocess() {
+ // TODO: split up preprocess steps into preprocess actions that can be toggled in a ui
+ extraAttribs.remove("timestamp")
+ extraAttribs.remove("uuid")
+ extraAttribs.remove("modifier")
+ extraAttribs.getString("petInfo").ifPresent { petInfoJson ->
+ var petInfo = Firmament.json.decodeFromString<HypixelPetInfo>(petInfoJson)
+ petInfo = petInfo.copy(candyUsed = 0, heldItem = null, exp = 0.0, active = null, uuid = null)
+ extraAttribs.putString("petInfo", Firmament.tightJson.encodeToString(petInfo))
+ }
+ itemStack.skyBlockId?.let {
+ extraAttribs.putString("id", it.neuItem)
+ }
+ trimLore()
+ itemStack.loreAccordingToNbt = itemStack.item.defaultStack.loreAccordingToNbt
+ itemStack.remove(DataComponentTypes.CUSTOM_NAME)
+ }
+
+ fun trimLore() {
+ val rarityIdx = lore.indexOfLast {
+ val firstWordInLine = it.unformattedString.words().filter { it.length > 2 }.firstOrNull()
+ firstWordInLine?.let(Rarity::fromString) != null
+ }
+ if (rarityIdx >= 0) {
+ lore = lore.subList(0, rarityIdx + 1)
+ }
+ deleteLineUntilNextSpace { it.startsWith("Held Item: ") }
+ deleteLineUntilNextSpace { it.startsWith("Progress to Level ") }
+ deleteLineUntilNextSpace { it.startsWith("MAX LEVEL") }
+ collapseWhitespaces()
+
+ name = name.transformEachRecursively {
+ var string = it.directLiteralStringContent ?: return@transformEachRecursively it
+ string = string.replace("Lvl \\d+".toRegex(), "Lvl {LVL}")
+ Text.literal(string).setStyle(it.style)
+ }
+ }
+
+ fun collapseWhitespaces() {
+ lore = (listOf(null as Text?) + lore).zipWithNext()
+ .filter { !it.first?.unformattedString.isNullOrBlank() || !it.second?.unformattedString.isNullOrBlank() }
+ .map { it.second!! }
+ }
+
+ fun deleteLineUntilNextSpace(search: (String) -> Boolean) {
+ val idx = lore.indexOfFirst { search(it.unformattedString) }
+ if (idx < 0) return
+ val l = lore.toMutableList()
+ val p = l.subList(idx, l.size)
+ val nextBlank = p.indexOfFirst { it.unformattedString.isEmpty() }
+ if (nextBlank < 0)
+ p.clear()
+ else
+ p.subList(0, nextBlank).clear()
+ lore = l
+ }
+
+ fun processNbt() {
+ // TODO: calculate hideflags
+ legacyNbt.put("HideFlags", NbtInt.of(254))
+ copyUnbreakable()
+ copyItemModel()
+ copyExtraAttributes()
+ copyLegacySkullNbt()
+ copyDisplay()
+ copyEnchantments()
+ copyEnchantGlint()
+ // TODO: copyDisplay
+ }
+
+ private fun copyItemModel() {
+ val itemModel = itemStack.get(DataComponentTypes.ITEM_MODEL) ?: return
+ legacyNbt.put("ItemModel", NbtString.of(itemModel.toString()))
+ }
+
+ private fun copyDisplay() {
+ legacyNbt.put("display", NbtCompound().apply {
+ put("Lore", lore.map { NbtString.of(it.getLegacyFormatString(trimmed = true)) }.toNbtList())
+ putString("Name", name.getLegacyFormatString(trimmed = true))
+ })
+ }
+
+ fun exportModernSnbt(): NbtElement {
+ val overlay = ItemStack.CODEC.encodeStart(NbtOps.INSTANCE, itemStack)
+ .orThrow
+ val overlayWithVersion =
+ ExportedTestConstantMeta.SOURCE_CODEC.encode(ExportedTestConstantMeta.current, NbtOps.INSTANCE, overlay)
+ .orThrow
+ return overlayWithVersion
+ }
+
+ fun prepare() {
+ preprocess()
+ processNbt()
+ }
+
+ fun exportJson(): JsonElement {
+ return buildJsonObject {
+ val (itemId, damage) = legacyifyItemStack()
+ put("itemid", itemId)
+ put("displayname", name.getLegacyFormatString(trimmed = true))
+ put("nbttag", legacyNbt.toLegacyString())
+ put("damage", damage)
+ put("lore", lore.map { it.getLegacyFormatString(trimmed = true) }.toJsonArray())
+ val sbId = itemStack.skyBlockId
+ if (sbId == null)
+ warnings.add("Could not find skyblock id")
+ put("internalname", sbId?.neuItem)
+ put("clickcommand", "")
+ put("crafttext", "")
+ put("modver", "Firmament ${Firmament.version.friendlyString}")
+ put("infoType", "")
+ put("info", JsonArray(listOf()))
+ }
+
+ }
+
+ companion object {
+ fun createExporter(itemStack: ItemStack): LegacyItemExporter {
+ return LegacyItemExporter(itemStack.copy()).also { it.prepare() }
+ }
+
+ @Subscribe
+ fun load(event: ClientStartedEvent) {
+ thread(start = true, name = "ItemExporter Meta Load Thread") {
+ LegacyItemData.itemLut
+ }
+ }
+ }
+
+ fun copyEnchantGlint() {
+ if (itemStack.get(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE) == true) {
+ val ench = legacyNbt.getListOrEmpty("ench")
+ legacyNbt.put("ench", ench)
+ }
+ }
+
+ private fun copyUnbreakable() {
+ if (itemStack.get(DataComponentTypes.UNBREAKABLE) == Unit.INSTANCE) {
+ legacyNbt.putBoolean("Unbreakable", true)
+ }
+ }
+
+ fun copyEnchantments() {
+ val enchantments = itemStack.get(DataComponentTypes.ENCHANTMENTS)?.takeIf { !it.isEmpty } ?: return
+ val enchTag = legacyNbt.getListOrEmpty("ench")
+ legacyNbt.put("ench", enchTag)
+ enchantments.enchantmentEntries.forEach { entry ->
+ val id = entry.key.key.get().value
+ val legacyId = LegacyItemData.enchantmentLut[id]
+ if (legacyId == null) {
+ warnings.add("Could not find legacy enchantment id for ${id}")
+ return@forEach
+ }
+ enchTag.add(NbtCompound().apply {
+ putShort("lvl", entry.intValue.toShort())
+ putShort(
+ "id",
+ legacyId.id.toShort()
+ )
+ })
+ }
+ }
+
+ fun copyExtraAttributes() {
+ legacyNbt.put("ExtraAttributes", extraAttribs)
+ }
+
+ fun copyLegacySkullNbt() {
+ val profile = itemStack.get(DataComponentTypes.PROFILE) ?: return
+ legacyNbt.put("SkullOwner", NbtCompound().apply {
+ profile.id.ifPresent {
+ putString("Id", it.toString())
+ }
+ putBoolean("hypixelPopulated", true)
+ put("Properties", NbtCompound().apply {
+ profile.properties().forEach { prop, value ->
+ val list = getListOrEmpty(prop)
+ put(prop, list)
+ list.add(NbtCompound().apply {
+ value.signature?.let {
+ putString("Signature", it)
+ }
+ putString("Value", value.value)
+ putString("Name", value.name)
+ })
+ }
+ })
+ })
+ }
+
+ fun legacyifyItemStack(): LegacyItemData.LegacyItemType {
+ // TODO: add a default here
+ return LegacyItemData.itemLut[itemStack.item]!!
+ }
+}