diff options
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/kotlin/features/debug/PowerUserTools.kt | 1 | ||||
-rw-r--r-- | src/main/kotlin/features/debug/itemeditor/ItemExporter.kt | 70 | ||||
-rw-r--r-- | src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt | 14 | ||||
-rw-r--r-- | src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt | 40 | ||||
-rw-r--r-- | src/main/kotlin/util/SkyblockId.kt | 7 | ||||
-rw-r--r-- | src/main/kotlin/util/StringUtil.kt | 6 | ||||
-rw-r--r-- | src/main/resources/legacy_data/effects.json | 140 |
7 files changed, 257 insertions, 21 deletions
diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt index 7c1df3f..1a7b2cf 100644 --- a/src/main/kotlin/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/features/debug/PowerUserTools.kt @@ -59,6 +59,7 @@ object PowerUserTools : FirmamentFeature { 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 } } override val config diff --git a/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt index 37875fb..c521b5a 100644 --- a/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt +++ b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt @@ -1,6 +1,5 @@ package moe.nea.firmament.features.debug.itemeditor -import com.mojang.brigadier.arguments.StringArgumentType import kotlinx.coroutines.launch import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject @@ -19,13 +18,14 @@ import net.minecraft.nbt.NbtString import net.minecraft.text.Text import moe.nea.firmament.Firmament import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.commands.RestArgumentType import moe.nea.firmament.commands.get -import moe.nea.firmament.commands.suggestsList import moe.nea.firmament.commands.thenArgument import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.commands.thenLiteral import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.HandledScreenKeyPressedEvent +import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.features.debug.DeveloperFeatures import moe.nea.firmament.features.debug.ExportedTestConstantMeta import moe.nea.firmament.features.debug.PowerUserTools @@ -40,6 +40,7 @@ import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString 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.render.drawGuiTexture import moe.nea.firmament.util.setSkyBlockId import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.tr @@ -47,6 +48,7 @@ import moe.nea.firmament.util.tr object ItemExporter { fun exportItem(itemStack: ItemStack): Text { + nonOverlayCache.clear() val exporter = LegacyItemExporter.createExporter(itemStack) var json = exporter.exportJson() val fileName = json.jsonObject["internalname"]!!.jsonPrimitive.content @@ -116,25 +118,42 @@ object ItemExporter { fun onCommand(event: CommandEvent.SubCommand) { event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) { thenLiteral("reexportlore") { - thenArgument("itemid", StringArgumentType.string()) { itemid -> - suggestsList { RepoManager.neuRepo.items.items.keys } + thenArgument("itemid", RestArgumentType) { itemid -> + suggests { ctx, builder -> + val spaceIndex = builder.remaining.lastIndexOf(" ") + val (before, after) = + if (spaceIndex < 0) Pair("", builder.remaining) + else Pair( + builder.remaining.substring(0, spaceIndex + 1), + builder.remaining.substring(spaceIndex + 1) + ) + RepoManager.neuRepo.items.items.keys + .asSequence() + .filter { it.startsWith(after, ignoreCase = true) } + .forEach { + builder.suggest(before + it) + } + + builder.buildFuture() + } thenExecute { - val itemid = SkyblockId(get(itemid)) - if (pathFor(itemid).notExists()) { + for (itemid in get(itemid).split(" ").map { SkyblockId(it) }) { + if (pathFor(itemid).notExists()) { + MC.sendChat( + tr( + "firmament.repo.export.relore.fail", + "Could not find json file to relore for ${itemid}" + ) + ) + } + fixLoreNbtFor(itemid) MC.sendChat( tr( - "firmament.repo.export.relore.fail", - "Could not find json file to relore for ${itemid}" + "firmament.repo.export.relore", + "Updated lore / display name for $itemid" ) ) } - fixLoreNbtFor(itemid) - MC.sendChat( - tr( - "firmament.repo.export.relore", - "Updated lore / display name for $itemid" - ) - ) } } thenLiteral("all") { @@ -188,6 +207,27 @@ object ItemExporter { } } + val nonOverlayCache = mutableMapOf<SkyblockId, Boolean>() + + @Subscribe + fun onRender(event: SlotRenderEvents.Before) { + if (!PowerUserTools.TConfig.highlightNonOverlayItems) { + return + } + val stack = event.slot.stack ?: return + val isExported = nonOverlayCache.getOrPut(stack.skyBlockId ?: return) { + RepoDownloadManager.repoSavedLocation.resolve("itemsOverlay") + .resolve(ExportedTestConstantMeta.current.dataVersion.toString()) + .resolve("${stack.skyBlockId}.snbt") + .exists() + } + if (!isExported) + event.context.drawGuiTexture( + Firmament.identifier("selected_pet_background"), + event.slot.x, event.slot.y, 16, 16, + ) + } + fun exportStub(skyblockId: SkyblockId, title: String, extra: (ItemStack) -> Unit = {}) { exportItem(ItemStack(Items.PLAYER_HEAD).also { it.displayNameAccordingToNbt = Text.literal(title) diff --git a/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt b/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt index c0f48ca..bc8c618 100644 --- a/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt +++ b/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt @@ -9,6 +9,7 @@ import moe.nea.firmament.Firmament import moe.nea.firmament.repo.ExpensiveItemCacheApi import moe.nea.firmament.repo.ItemCache import moe.nea.firmament.util.MC +import moe.nea.firmament.util.StringUtil.camelWords /** * Load data based on [prismarine.js' 1.8 item data](https://github.com/PrismarineJS/minecraft-data/blob/master/data/pc/1.8/items.json) @@ -58,6 +59,7 @@ object LegacyItemData { val enchantmentLut = enchantmentData.associateBy { Identifier.ofVanilla(it.name) } val itemDat = getLegacyData<List<ItemData>>("items") + @OptIn(ExpensiveItemCacheApi::class) // This is fine, we get loaded in a thread. val itemLut = itemDat.flatMap { item -> item.allVariants().map { legacyItemType -> @@ -72,4 +74,16 @@ object LegacyItemData { } }.toMap() + @Serializable + data class LegacyEffect( + val id: Int, + val name: String, + val displayName: String, + val type: String + ) + + val effectList = getLegacyData<List<LegacyEffect>>("effects") + .associateBy { + it.name.camelWords().map { it.trim().lowercase() }.joinToString("_") + } } diff --git a/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt index 3cd1ce8..ad03b16 100644 --- a/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt +++ b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt @@ -7,9 +7,11 @@ import kotlinx.serialization.json.put import kotlin.concurrent.thread import net.minecraft.component.DataComponentTypes import net.minecraft.item.ItemStack +import net.minecraft.nbt.NbtByte import net.minecraft.nbt.NbtCompound import net.minecraft.nbt.NbtElement import net.minecraft.nbt.NbtInt +import net.minecraft.nbt.NbtList import net.minecraft.nbt.NbtOps import net.minecraft.nbt.NbtString import net.minecraft.text.Text @@ -36,8 +38,9 @@ import moe.nea.firmament.util.unformattedString class LegacyItemExporter private constructor(var itemStack: ItemStack) { init { - require(!itemStack.isEmpty) + require(!itemStack.isEmpty) } + var lore = itemStack.loreAccordingToNbt var name = itemStack.displayNameAccordingToNbt val extraAttribs = itemStack.extraAttributes.copy() @@ -133,24 +136,55 @@ class LegacyItemExporter private constructor(var itemStack: ItemStack) { legacyNbt.put("HideFlags", NbtInt.of(254)) copyUnbreakable() copyItemModel() + copyPotion() copyExtraAttributes() copyLegacySkullNbt() copyDisplay() + copyColour() copyEnchantments() copyEnchantGlint() // TODO: copyDisplay } + private fun copyPotion() { + val effects = itemStack.get(DataComponentTypes.POTION_CONTENTS) ?: return + legacyNbt.put("CustomPotionEffects", NbtList().also { + effects.effects.forEach { effect -> + val effectId = effect.effectType.key.get().value.path + val duration = effect.duration + val legacyId = LegacyItemData.effectList[effectId]!! + + it.add(NbtCompound().apply { + put("Ambient", NbtByte.of(false)) + put("Duration", NbtInt.of(duration)) + put("Id", NbtByte.of(legacyId.id.toByte())) + put("Amplifier", NbtByte.of(effect.amplifier.toByte())) + }) + } + }) + } + + fun NbtCompound.getOrPutCompound(name: String): NbtCompound { + val compound = getCompoundOrEmpty(name) + put(name, compound) + return compound + } + + private fun copyColour() { + val leatherTint = itemStack.get(DataComponentTypes.DYED_COLOR) ?: return + legacyNbt.getOrPutCompound("display").put("color", NbtInt.of(leatherTint.rgb)) + } + 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 { + legacyNbt.getOrPutCompound("display").apply { put("Lore", lore.map { NbtString.of(it.getLegacyFormatString(trimmed = true)) }.toNbtList()) putString("Name", name.getLegacyFormatString(trimmed = true)) - }) + } } fun exportModernSnbt(): NbtElement { diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt index b4d583a..051ca86 100644 --- a/src/main/kotlin/util/SkyblockId.kt +++ b/src/main/kotlin/util/SkyblockId.kt @@ -251,10 +251,11 @@ val ItemStack.skyBlockId: SkyblockId? val potionName = extraAttributes.getString("potion_name").getOrNull() val potionLevel = extraAttributes.getInt("potion_level").getOrNull() val potionType = extraAttributes.getString("potion_type").getOrNull() + fun String.potionNormalize() = uppercase().replace(" ", "_") when { - potionName != null -> SkyblockId("POTION_${potionName.uppercase()};$potionLevel") - potionData != null -> SkyblockId("POTION_${potionData.uppercase()};$potionLevel") - potionType != null -> SkyblockId("POTION_${potionType.uppercase()}") + potionName != null -> SkyblockId("POTION_${potionName.potionNormalize()};$potionLevel") + potionData != null -> SkyblockId("POTION_${potionData.potionNormalize()};$potionLevel") + potionType != null -> SkyblockId("POTION_${potionType.potionNormalize()}") else -> SkyblockId("WATER_BOTTLE") } } diff --git a/src/main/kotlin/util/StringUtil.kt b/src/main/kotlin/util/StringUtil.kt index dc98dc0..50c5367 100644 --- a/src/main/kotlin/util/StringUtil.kt +++ b/src/main/kotlin/util/StringUtil.kt @@ -5,6 +5,12 @@ object StringUtil { return splitToSequence(" ") // TODO: better boundaries } + fun String.camelWords(): Sequence<String> { + return splitToSequence(camelWordStart) + } + + private val camelWordStart = Regex("((?<=[a-z])(?=[A-Z]))| ") + fun parseIntWithComma(string: String): Int { return string.replace(",", "").toInt() } diff --git a/src/main/resources/legacy_data/effects.json b/src/main/resources/legacy_data/effects.json new file mode 100644 index 0000000..0b885b5 --- /dev/null +++ b/src/main/resources/legacy_data/effects.json @@ -0,0 +1,140 @@ +[ + { + "id": 1, + "name": "Speed", + "displayName": "Speed", + "type": "good" + }, + { + "id": 2, + "name": "Slowness", + "displayName": "Slowness", + "type": "bad" + }, + { + "id": 3, + "name": "Haste", + "displayName": "Haste", + "type": "good" + }, + { + "id": 4, + "name": "MiningFatigue", + "displayName": "Mining Fatigue", + "type": "bad" + }, + { + "id": 5, + "name": "Strength", + "displayName": "Strength", + "type": "good" + }, + { + "id": 6, + "name": "InstantHealth", + "displayName": "Instant Health", + "type": "good" + }, + { + "id": 7, + "name": "InstantDamage", + "displayName": "Instant Damage", + "type": "bad" + }, + { + "id": 8, + "name": "JumpBoost", + "displayName": "Jump Boost", + "type": "good" + }, + { + "id": 9, + "name": "Nausea", + "displayName": "Nausea", + "type": "bad" + }, + { + "id": 10, + "name": "Regeneration", + "displayName": "Regeneration", + "type": "good" + }, + { + "id": 11, + "name": "Resistance", + "displayName": "Resistance", + "type": "good" + }, + { + "id": 12, + "name": "FireResistance", + "displayName": "Fire Resistance", + "type": "good" + }, + { + "id": 13, + "name": "WaterBreathing", + "displayName": "Water Breathing", + "type": "good" + }, + { + "id": 14, + "name": "Invisibility", + "displayName": "Invisibility", + "type": "good" + }, + { + "id": 15, + "name": "Blindness", + "displayName": "Blindness", + "type": "bad" + }, + { + "id": 16, + "name": "NightVision", + "displayName": "Night Vision", + "type": "good" + }, + { + "id": 17, + "name": "Hunger", + "displayName": "Hunger", + "type": "bad" + }, + { + "id": 18, + "name": "Weakness", + "displayName": "Weakness", + "type": "bad" + }, + { + "id": 19, + "name": "Poison", + "displayName": "Poison", + "type": "bad" + }, + { + "id": 20, + "name": "Wither", + "displayName": "Wither", + "type": "bad" + }, + { + "id": 21, + "name": "HealthBoost", + "displayName": "Health Boost", + "type": "good" + }, + { + "id": 22, + "name": "Absorption", + "displayName": "Absorption", + "type": "good" + }, + { + "id": 23, + "name": "Saturation", + "displayName": "Saturation", + "type": "good" + } +] |