aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MinecraftInitLevelListener.java26
-rw-r--r--src/main/kotlin/Firmament.kt2
-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
-rw-r--r--src/main/kotlin/gui/config/ManagedOption.kt2
-rw-r--r--src/main/kotlin/keybindings/SavedKeyBinding.kt8
-rw-r--r--src/main/kotlin/repo/ItemCache.kt50
-rw-r--r--src/main/kotlin/repo/ModernOverlaysData.kt39
-rw-r--r--src/main/kotlin/repo/RepoManager.kt2
-rw-r--r--src/main/kotlin/util/ErrorUtil.kt11
-rw-r--r--src/main/kotlin/util/mc/InitLevel.kt25
12 files changed, 430 insertions, 248 deletions
diff --git a/src/main/java/moe/nea/firmament/mixins/MinecraftInitLevelListener.java b/src/main/java/moe/nea/firmament/mixins/MinecraftInitLevelListener.java
new file mode 100644
index 0000000..550180a
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/MinecraftInitLevelListener.java
@@ -0,0 +1,26 @@
+package moe.nea.firmament.mixins;
+
+import moe.nea.firmament.util.mc.InitLevel;
+import net.minecraft.client.MinecraftClient;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(MinecraftClient.class)
+public class MinecraftInitLevelListener {
+ @Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;initBackendSystem()Lnet/minecraft/util/TimeSupplier$Nanoseconds;"))
+ private void onInitRenderBackend(CallbackInfo ci) {
+ InitLevel.bump(InitLevel.RENDER_INIT);
+ }
+
+ @Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;initRenderer(JIZLjava/util/function/BiFunction;Z)V"))
+ private void onInitRender(CallbackInfo ci) {
+ InitLevel.bump(InitLevel.RENDER);
+ }
+
+ @Inject(method = "onFinishedLoading", at = @At(value = "HEAD"))
+ private void onFinishedLoading(CallbackInfo ci) {
+ InitLevel.bump(InitLevel.MAIN_MENU);
+ }
+}
diff --git a/src/main/kotlin/Firmament.kt b/src/main/kotlin/Firmament.kt
index 717808f..b00546a 100644
--- a/src/main/kotlin/Firmament.kt
+++ b/src/main/kotlin/Firmament.kt
@@ -51,6 +51,7 @@ import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.data.IDataHolder
+import moe.nea.firmament.util.mc.InitLevel
import moe.nea.firmament.util.tr
object Firmament {
@@ -134,6 +135,7 @@ object Firmament {
@JvmStatic
fun onClientInitialize() {
+ InitLevel.bump(InitLevel.MC_INIT)
FeatureManager.subscribeEvents()
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance ->
TickEvent.publish(TickEvent(MC.currentTick++))
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]!!
+ }
+}
diff --git a/src/main/kotlin/gui/config/ManagedOption.kt b/src/main/kotlin/gui/config/ManagedOption.kt
index 383f392..830086c 100644
--- a/src/main/kotlin/gui/config/ManagedOption.kt
+++ b/src/main/kotlin/gui/config/ManagedOption.kt
@@ -49,7 +49,7 @@ class ManagedOption<T : Any>(
value = handler.fromJson(root[propertyName]!!)
return
} catch (e: Exception) {
- ErrorUtil.softError(
+ ErrorUtil.logError(
"Exception during loading of config file ${element.name}. This will reset this config.",
e
)
diff --git a/src/main/kotlin/keybindings/SavedKeyBinding.kt b/src/main/kotlin/keybindings/SavedKeyBinding.kt
index fc0270d..01baa8f 100644
--- a/src/main/kotlin/keybindings/SavedKeyBinding.kt
+++ b/src/main/kotlin/keybindings/SavedKeyBinding.kt
@@ -6,6 +6,7 @@ import net.minecraft.client.MinecraftClient
import net.minecraft.client.util.InputUtil
import net.minecraft.text.Text
import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.mc.InitLevel
// TODO: add support for mouse keybindings
@Serializable
@@ -113,8 +114,11 @@ data class SavedKeyBinding(
if (shift) {
stroke.append("SHIFT + ") // TODO: translations?
}
-
- stroke.append(InputUtil.Type.KEYSYM.createFromCode(keyCode).localizedText)
+ if (InitLevel.isAtLeast(InitLevel.RENDER_INIT)) {
+ stroke.append(InputUtil.Type.KEYSYM.createFromCode(keyCode).localizedText)
+ } else {
+ stroke.append(keyCode.toString())
+ }
return stroke
}
diff --git a/src/main/kotlin/repo/ItemCache.kt b/src/main/kotlin/repo/ItemCache.kt
index 15b3a27..3518257 100644
--- a/src/main/kotlin/repo/ItemCache.kt
+++ b/src/main/kotlin/repo/ItemCache.kt
@@ -16,6 +16,7 @@ import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import kotlin.io.path.readText
import kotlin.jvm.optionals.getOrNull
import net.minecraft.SharedConstants
import net.minecraft.component.DataComponentTypes
@@ -28,11 +29,13 @@ import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtElement
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.NbtString
+import net.minecraft.nbt.StringNbtReader
import net.minecraft.text.MutableText
import net.minecraft.text.Style
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament
+import moe.nea.firmament.features.debug.ExportedTestConstantMeta
import moe.nea.firmament.repo.RepoManager.initialize
import moe.nea.firmament.util.LegacyFormattingCode
import moe.nea.firmament.util.LegacyTagParser
@@ -67,6 +70,7 @@ object ItemCache : IReloadable {
@ExpensiveItemCacheApi
private fun NbtCompound.transformFrom10809ToModern() = convert189ToModern(this@transformFrom10809ToModern)
+ val currentSaveVersion = SharedConstants.getGameVersion().saveVersion.id
@ExpensiveItemCacheApi
fun convert189ToModern(nbtComponent: NbtCompound): NbtCompound? =
@@ -75,7 +79,7 @@ object ItemCache : IReloadable {
TypeReferences.ITEM_STACK,
Dynamic(NbtOps.INSTANCE, nbtComponent),
-1,
- SharedConstants.getGameVersion().saveVersion.id
+ currentSaveVersion
).value as NbtCompound
} catch (e: Exception) {
isFlawless = false
@@ -138,24 +142,48 @@ object ItemCache : IReloadable {
return base
}
+ fun tryFindFromModernFormat(skyblockId: SkyblockId): NbtCompound? {
+ val overlayFile =
+ RepoManager.overlayData.getMostModernReadableOverlay(skyblockId, currentSaveVersion) ?: return null
+ val overlay = StringNbtReader.readCompound(overlayFile.path.readText())
+ val result = ExportedTestConstantMeta.SOURCE_CODEC.decode(
+ NbtOps.INSTANCE, overlay
+ ).result().getOrNull() ?: return null
+ val meta = result.first
+ return df.update(
+ TypeReferences.ITEM_STACK,
+ Dynamic(NbtOps.INSTANCE, result.second),
+ meta.dataVersion,
+ currentSaveVersion
+ ).value as NbtCompound
+ }
+
@ExpensiveItemCacheApi
private fun NEUItem.asItemStackNow(): ItemStack {
+
try {
+ var modernItemTag = tryFindFromModernFormat(this.skyblockId)
val oldItemTag = get10809CompoundTag()
- val modernItemTag = oldItemTag.transformFrom10809ToModern()
- ?: return brokenItemStack(this)
+ var usedOldNbt = false
+ if (modernItemTag == null) {
+ usedOldNbt = true
+ modernItemTag = oldItemTag.transformFrom10809ToModern()
+ ?: return brokenItemStack(this)
+ }
val itemInstance =
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
+ if (usedOldNbt) {
+ val tag = oldItemTag.getCompound("tag")
+ val extraAttributes = tag.flatMap { it.getCompound("ExtraAttributes") }
+ .getOrNull()
+ if (extraAttributes != null)
+ itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes))
+ val itemModel = tag.flatMap { it.getString("ItemModel") }.getOrNull()
+ if (itemModel != null)
+ itemInstance.set(DataComponentTypes.ITEM_MODEL, Identifier.of(itemModel))
+ }
itemInstance.loreAccordingToNbt = lore.map { un189Lore(it) }
itemInstance.displayNameAccordingToNbt = un189Lore(displayName)
- val tag = oldItemTag.getCompound("tag")
- val extraAttributes = tag.flatMap { it.getCompound("ExtraAttributes") }
- .getOrNull()
- if (extraAttributes != null)
- itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes))
- val itemModel = tag.flatMap { it.getString("ItemModel") }.getOrNull()
- if (itemModel != null)
- itemInstance.set(DataComponentTypes.ITEM_MODEL, Identifier.of(itemModel))
return itemInstance
} catch (e: Exception) {
e.printStackTrace()
diff --git a/src/main/kotlin/repo/ModernOverlaysData.kt b/src/main/kotlin/repo/ModernOverlaysData.kt
new file mode 100644
index 0000000..7e7acf1
--- /dev/null
+++ b/src/main/kotlin/repo/ModernOverlaysData.kt
@@ -0,0 +1,39 @@
+package moe.nea.firmament.repo
+
+import io.github.moulberry.repo.IReloadable
+import io.github.moulberry.repo.NEURepository
+import java.nio.file.Path
+import kotlin.io.path.extension
+import kotlin.io.path.listDirectoryEntries
+import kotlin.io.path.nameWithoutExtension
+import moe.nea.firmament.util.SkyblockId
+
+// TODO: move this over to the repo parser
+class ModernOverlaysData : IReloadable {
+ data class OverlayFile(
+ val version: Int,
+ val path: Path,
+ )
+
+ var overlays: Map<SkyblockId, List<OverlayFile>> = mapOf()
+ override fun reload(repo: NEURepository) {
+ val items = mutableMapOf<SkyblockId, MutableList<OverlayFile>>()
+ repo.baseFolder.resolve("itemsOverlay")
+ .listDirectoryEntries()
+ .forEach { versionFolder ->
+ val version = versionFolder.fileName.toString().toIntOrNull() ?: return@forEach
+ versionFolder.listDirectoryEntries()
+ .forEach { item ->
+ if (item.extension != "snbt") return@forEach
+ val itemId = item.nameWithoutExtension
+ items.getOrPut(SkyblockId(itemId)) { mutableListOf() }.add(OverlayFile(version, item))
+ }
+ }
+ this.overlays = items
+ }
+
+ fun getOverlayFiles(skyblockId: SkyblockId) = overlays[skyblockId] ?: listOf()
+ fun getMostModernReadableOverlay(skyblockId: SkyblockId, version: Int) = getOverlayFiles(skyblockId)
+ .filter { it.version <= version }
+ .maxByOrNull { it.version }
+}
diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt
index f4146e0..df89092 100644
--- a/src/main/kotlin/repo/RepoManager.kt
+++ b/src/main/kotlin/repo/RepoManager.kt
@@ -66,9 +66,11 @@ object RepoManager {
val essenceRecipeProvider = EssenceRecipeProvider()
val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider, ReforgeStore)
val miningData = MiningRepoData()
+ val overlayData = ModernOverlaysData()
fun makeNEURepository(path: Path): NEURepository {
return NEURepository.of(path).apply {
+ registerReloadListener(overlayData)
registerReloadListener(ItemCache)
registerReloadListener(RepoItemTypeCache)
registerReloadListener(ExpLadders)
diff --git a/src/main/kotlin/util/ErrorUtil.kt b/src/main/kotlin/util/ErrorUtil.kt
index f12bb12..3db4ecd 100644
--- a/src/main/kotlin/util/ErrorUtil.kt
+++ b/src/main/kotlin/util/ErrorUtil.kt
@@ -29,12 +29,19 @@ object ErrorUtil {
inline fun softError(message: String, exception: Throwable) {
if (aggressiveErrors) throw IllegalStateException(message, exception)
- else Firmament.logger.error(message, exception)
+ else logError(message, exception)
+ }
+
+ fun logError(message: String, exception: Throwable) {
+ Firmament.logger.error(message, exception)
+ }
+ fun logError(message: String) {
+ Firmament.logger.error(message)
}
inline fun softError(message: String) {
if (aggressiveErrors) error(message)
- else Firmament.logger.error(message)
+ else logError(message)
}
fun <T> Result<T>.intoCatch(message: String): Catch<T> {
diff --git a/src/main/kotlin/util/mc/InitLevel.kt b/src/main/kotlin/util/mc/InitLevel.kt
new file mode 100644
index 0000000..2c3eedb
--- /dev/null
+++ b/src/main/kotlin/util/mc/InitLevel.kt
@@ -0,0 +1,25 @@
+package moe.nea.firmament.util.mc
+
+enum class InitLevel {
+ STARTING,
+ MC_INIT,
+ RENDER_INIT,
+ RENDER,
+ MAIN_MENU,
+ ;
+
+ companion object {
+ var initLevel = InitLevel.STARTING
+ private set
+
+ @JvmStatic
+ fun isAtLeast(wantedLevel: InitLevel): Boolean = initLevel >= wantedLevel
+
+ @JvmStatic
+ fun bump(nextLevel: InitLevel) {
+ if (nextLevel.ordinal != initLevel.ordinal + 1)
+ error("Cannot bump initLevel $nextLevel from $initLevel")
+ initLevel = nextLevel
+ }
+ }
+}