feat: Add crafting recipe exporter

This commit is contained in:
Linnea Gräf
2025-06-22 20:25:46 +02:00
parent 05ca14b623
commit 89047619c6
3 changed files with 106 additions and 25 deletions

View File

@@ -57,6 +57,7 @@ object PowerUserTools : FirmamentFeature {
val copyItemStack by keyBindingWithDefaultUnbound("copy-item-stack") val copyItemStack by keyBindingWithDefaultUnbound("copy-item-stack")
val copyTitle by keyBindingWithDefaultUnbound("copy-title") val copyTitle by keyBindingWithDefaultUnbound("copy-title")
val exportItemStackToRepo by keyBindingWithDefaultUnbound("export-item-stack") val exportItemStackToRepo by keyBindingWithDefaultUnbound("export-item-stack")
val exportUIRecipes by keyBindingWithDefaultUnbound("export-recipe")
} }
override val config override val config

View File

@@ -0,0 +1,57 @@
package moe.nea.firmament.features.debug.itemeditor
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.features.debug.PowerUserTools
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.mc.ScreenUtil.getSlotByIndex
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.tr
object ExportRecipe {
val xNames = "ABC"
val yNames = "123"
val slotIndices = (0..<9).map {
val x = it % 3
val y = it / 3
(xNames[x].toString() + yNames[y]) to x + y * 9 + 10
}
val resultSlot = 25
@Subscribe
fun onRecipeKeyBind(event: HandledScreenKeyPressedEvent) {
if (!event.matches(PowerUserTools.TConfig.exportUIRecipes)) {
return
}
if (!event.screen.title.string.endsWith(" Recipe")) {
MC.sendChat(tr("firmament.repo.export.recipe.fail", "No Recipe found"))
return
}
slotIndices.forEach { (_, index) ->
event.screen.getSlotByIndex(index, false)?.stack?.let(ItemExporter::ensureExported)
}
val inputs = slotIndices.associate { (name, index) ->
val id = event.screen.getSlotByIndex(index, false)?.stack?.takeIf { !it.isEmpty() }?.let {
"${it.skyBlockId?.neuItem}:${it.count}"
} ?: ""
name to JsonPrimitive(id)
}
val output = event.screen.getSlotByIndex(resultSlot, false)?.stack!!
val overrideOutputId = output.skyBlockId!!.neuItem
val count = output.count
val recipe = JsonObject(
inputs + mapOf(
"type" to JsonPrimitive("crafting"),
"count" to JsonPrimitive(count),
"overrideOutputId" to JsonPrimitive(overrideOutputId)
)
)
ItemExporter.appendRecipe(output.skyBlockId!!, recipe)
}
}

View File

@@ -1,53 +1,76 @@
package moe.nea.firmament.features.debug.itemeditor package moe.nea.firmament.features.debug.itemeditor
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import kotlin.io.path.createParentDirectories import kotlin.io.path.createParentDirectories
import kotlin.io.path.exists
import kotlin.io.path.readText
import kotlin.io.path.relativeTo import kotlin.io.path.relativeTo
import kotlin.io.path.writeText import kotlin.io.path.writeText
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtOps import net.minecraft.text.Text
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenKeyPressedEvent import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.features.debug.ExportedTestConstantMeta import moe.nea.firmament.features.debug.ExportedTestConstantMeta
import moe.nea.firmament.features.debug.PowerUserTools import moe.nea.firmament.features.debug.PowerUserTools
import moe.nea.firmament.repo.RepoDownloadManager import moe.nea.firmament.repo.RepoDownloadManager
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.focusedItemStack import moe.nea.firmament.util.focusedItemStack
import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.tr import moe.nea.firmament.util.tr
object ItemExporter { object ItemExporter {
fun exportItem(itemStack: ItemStack): Text {
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())
return tr(
"firmament.repoexport.success",
"Exported item to ${itemFile.relativeTo(RepoDownloadManager.repoSavedLocation)}${
exporter.warnings.joinToString(
""
) { "\nWarning: $it" }
}"
)
}
fun pathFor(skyBlockId: SkyblockId) =
RepoManager.neuRepo.baseFolder.resolve("items/${skyBlockId.neuItem}.json")
fun ensureExported(itemStack: ItemStack) {
if (!pathFor(itemStack.skyBlockId ?: return).exists())
exportItem(itemStack)
}
fun appendRecipe(skyblockId: SkyblockId, recipe: JsonObject) {
val oldJson = Firmament.json.decodeFromString<JsonObject>(pathFor(skyblockId).readText())
val mutableJson = oldJson.toMutableMap()
val recipes = ((mutableJson["recipes"] as JsonArray?) ?: listOf()).toMutableList()
recipes.add(recipe)
mutableJson["recipes"] = JsonArray(recipes)
pathFor(skyblockId).writeText(Firmament.twoSpaceJson.encodeToString(JsonObject(mutableJson)))
}
@Subscribe @Subscribe
fun onKeyBind(event: HandledScreenKeyPressedEvent) { fun onKeyBind(event: HandledScreenKeyPressedEvent) {
if (event.matches(PowerUserTools.TConfig.exportItemStackToRepo)) { if (event.matches(PowerUserTools.TConfig.exportItemStackToRepo)) {
val itemStack = event.screen.focusedItemStack ?: return val itemStack = event.screen.focusedItemStack ?: return
val exporter = LegacyItemExporter.createExporter(itemStack) PowerUserTools.lastCopiedStack = (itemStack to exportItem(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" }
}"
)
)
} }
} }
} }