diff options
Diffstat (limited to 'src/main/kotlin/repo/ItemCache.kt')
| -rw-r--r-- | src/main/kotlin/repo/ItemCache.kt | 212 |
1 files changed, 126 insertions, 86 deletions
diff --git a/src/main/kotlin/repo/ItemCache.kt b/src/main/kotlin/repo/ItemCache.kt index e140dd8..be07042 100644 --- a/src/main/kotlin/repo/ItemCache.kt +++ b/src/main/kotlin/repo/ItemCache.kt @@ -4,70 +4,83 @@ import com.mojang.serialization.Dynamic import io.github.moulberry.repo.IReloadable import io.github.moulberry.repo.NEURepository import io.github.moulberry.repo.data.NEUItem -import io.github.notenoughupdates.moulconfig.xml.Bind import java.text.NumberFormat import java.util.UUID import java.util.concurrent.ConcurrentHashMap import org.apache.logging.log4j.LogManager -import kotlinx.coroutines.Job +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.async +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.client.resource.language.I18n -import net.minecraft.component.DataComponentTypes -import net.minecraft.component.type.NbtComponent -import net.minecraft.datafixer.Schemas -import net.minecraft.datafixer.TypeReferences -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.nbt.NbtCompound -import net.minecraft.nbt.NbtElement +import net.minecraft.core.component.DataComponents +import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.NbtOps -import net.minecraft.nbt.NbtString -import net.minecraft.text.Style -import net.minecraft.text.Text +import net.minecraft.nbt.StringTag +import net.minecraft.nbt.Tag +import net.minecraft.nbt.TagParser +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.MutableComponent +import net.minecraft.network.chat.Style +import net.minecraft.resources.ResourceLocation +import net.minecraft.util.datafix.DataFixers +import net.minecraft.util.datafix.fixes.References +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.item.component.CustomData import moe.nea.firmament.Firmament -import moe.nea.firmament.gui.config.HudMeta -import moe.nea.firmament.gui.config.HudPosition -import moe.nea.firmament.gui.hud.MoulConfigHud +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 -import moe.nea.firmament.util.MC +import moe.nea.firmament.util.MinecraftDispatcher import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.TestUtil import moe.nea.firmament.util.directLiteralStringContent import moe.nea.firmament.util.mc.FirmamentDataComponentTypes import moe.nea.firmament.util.mc.appendLore import moe.nea.firmament.util.mc.displayNameAccordingToNbt +import moe.nea.firmament.util.mc.loadItemFromNbt import moe.nea.firmament.util.mc.loreAccordingToNbt import moe.nea.firmament.util.mc.modifyLore import moe.nea.firmament.util.mc.setCustomName import moe.nea.firmament.util.mc.setSkullOwner +import moe.nea.firmament.util.skyblockId import moe.nea.firmament.util.transformEachRecursively object ItemCache : IReloadable { private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap() - private val df = Schemas.getFixer() + private val df = DataFixers.getDataFixer() val logger = LogManager.getLogger("${Firmament.logger.name}.ItemCache") var isFlawless = true private set - private fun NEUItem.get10809CompoundTag(): NbtCompound = NbtCompound().apply { + private fun NEUItem.get10809CompoundTag(): CompoundTag = CompoundTag().apply { put("tag", LegacyTagParser.parse(nbttag)) putString("id", minecraftItemId) putByte("Count", 1) putShort("Damage", damage.toShort()) } - private fun NbtCompound.transformFrom10809ToModern(): NbtCompound? = + @ExpensiveItemCacheApi + private fun CompoundTag.transformFrom10809ToModern() = convert189ToModern(this@transformFrom10809ToModern) + val currentSaveVersion = SharedConstants.getCurrentVersion().dataVersion().version + + @ExpensiveItemCacheApi + fun convert189ToModern(nbtComponent: CompoundTag): CompoundTag? = try { df.update( - TypeReferences.ITEM_STACK, - Dynamic(NbtOps.INSTANCE, this), + References.ITEM_STACK, + Dynamic(NbtOps.INSTANCE, nbtComponent), -1, - SharedConstants.getGameVersion().saveVersion.id - ).value as NbtCompound + currentSaveVersion + ).value as CompoundTag } catch (e: Exception) { isFlawless = false logger.error("Could not data fix up $this", e) @@ -84,24 +97,24 @@ object ItemCache : IReloadable { fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack { return ItemStack(Items.PAINTING).apply { - setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null")) + setCustomName(Component.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null")) appendLore( listOf( - Text.stringifiedTranslatable( + Component.translatableEscape( "firmament.repo.brokenitem", (neuItem?.skyblockItemId ?: idHint) ) ) ) - set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(NbtCompound().apply { - put("ID", NbtString.of(neuItem?.skyblockItemId ?: idHint?.neuItem ?: "null")) + set(DataComponents.CUSTOM_DATA, CustomData.of(CompoundTag().apply { + put("ID", StringTag.valueOf(neuItem?.skyblockItemId ?: idHint?.neuItem ?: "null")) })) set(FirmamentDataComponentTypes.IS_BROKEN, true) } } - fun un189Lore(lore: String): Text { - val base = Text.literal("") + fun un189Lore(lore: String): MutableComponent { + val base = Component.literal("") base.setStyle(Style.EMPTY.withItalic(false)) var lastColorCode = Style.EMPTY var readOffset = 0 @@ -112,7 +125,7 @@ object ItemCache : IReloadable { } val text = lore.substring(readOffset, nextCode) if (text.isNotEmpty()) { - base.append(Text.literal(text).setStyle(lastColorCode)) + base.append(Component.literal(text).setStyle(lastColorCode)) } readOffset = nextCode + 2 if (nextCode + 1 < lore.length) { @@ -122,25 +135,55 @@ object ItemCache : IReloadable { if (modernFormatting.isColor) { lastColorCode = Style.EMPTY.withColor(modernFormatting) } else { - lastColorCode = lastColorCode.withFormatting(modernFormatting) + lastColorCode = lastColorCode.applyFormat(modernFormatting) } } } return base } + fun tryFindFromModernFormat(skyblockId: SkyblockId): CompoundTag? { + val overlayFile = + RepoManager.overlayData.getMostModernReadableOverlay(skyblockId, currentSaveVersion) ?: return null + val overlay = TagParser.parseCompoundFully(overlayFile.path.readText()) + val result = ExportedTestConstantMeta.SOURCE_CODEC.decode( + NbtOps.INSTANCE, overlay + ).result().getOrNull() ?: return null + val meta = result.first + return df.update( + References.ITEM_STACK, + Dynamic(NbtOps.INSTANCE, result.second), + meta.dataVersion, + currentSaveVersion + ).value as CompoundTag + } + + @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) + loadItemFromNbt( modernItemTag) ?: return brokenItemStack(this) + if (usedOldNbt) { + val tag = oldItemTag.getCompound("tag") + val extraAttributes = tag.flatMap { it.getCompound("ExtraAttributes") } + .getOrNull() + if (extraAttributes != null) + itemInstance.set(DataComponents.CUSTOM_DATA, CustomData.of(extraAttributes)) + val itemModel = tag.flatMap { it.getString("ItemModel") }.getOrNull() + if (itemModel != null) + itemInstance.set(DataComponents.ITEM_MODEL, ResourceLocation.parse(itemModel)) + } itemInstance.loreAccordingToNbt = lore.map { un189Lore(it) } itemInstance.displayNameAccordingToNbt = un189Lore(displayName) - val extraAttributes = oldItemTag.getCompound("tag").getCompound("ExtraAttributes") - if (extraAttributes != null) - itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes)) return itemInstance } catch (e: Exception) { e.printStackTrace() @@ -148,6 +191,11 @@ object ItemCache : IReloadable { } } + fun hasCacheFor(skyblockId: SkyblockId): Boolean { + return skyblockId.neuItem in cache + } + + @ExpensiveItemCacheApi fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack { if (this == null) return brokenItemStack(null, idHint) var s = cache[this.skyblockItemId] @@ -158,7 +206,7 @@ object ItemCache : IReloadable { if (!loreReplacements.isNullOrEmpty()) { s = s.copy()!! s.applyLoreReplacements(loreReplacements) - s.setCustomName(s.name.applyLoreReplacements(loreReplacements)) + s.setCustomName(s.hoverName.applyLoreReplacements(loreReplacements)) } return s } @@ -171,67 +219,59 @@ object ItemCache : IReloadable { } } - fun Text.applyLoreReplacements(loreReplacements: Map<String, String>): Text { + fun Component.applyLoreReplacements(loreReplacements: Map<String, String>): Component { return this.transformEachRecursively { var string = it.directLiteralStringContent ?: return@transformEachRecursively it loreReplacements.forEach { (find, replace) -> string = string.replace("{$find}", replace) } - Text.literal(string).setStyle(it.style) + Component.literal(string).setStyle(it.style) } } - var job: Job? = null - - object ReloadProgressHud : MoulConfigHud( - "repo_reload", HudMeta(HudPosition(0.0, 0.0, 1F), Text.literal("Repo Reload"), 180, 18)) { - - - var isEnabled = false - override fun shouldRender(): Boolean { - return isEnabled - } + var itemRecacheScope: CoroutineScope? = null - @get:Bind("current") - var current: Double = 0.0 + private var recacheSoonSubmitted = mutableSetOf<SkyblockId>() - @get:Bind("label") - var label: String = "" - - @get:Bind("max") - var max: Double = 0.0 - - fun reportProgress(label: String, current: Int, max: Int) { - this.label = label - this.current = current.toDouble() - this.max = max.toDouble() + @OptIn(ExpensiveItemCacheApi::class) + fun recacheSoon(neuItem: NEUItem) { + itemRecacheScope?.launch { + if (!withContext(MinecraftDispatcher) { + recacheSoonSubmitted.add(neuItem.skyblockId) + }) { + return@launch + } + neuItem.asItemStack() } } + @OptIn(ExpensiveItemCacheApi::class) override fun reload(repository: NEURepository) { - val j = job - if (j != null && j.isActive) { - j.cancel() - } + val j = itemRecacheScope + j?.cancel("New reload invoked") cache.clear() isFlawless = true if (TestUtil.isInTest) return - job = Firmament.coroutineScope.launch { - val items = repository.items?.items - if (items == null) { - ReloadProgressHud.isEnabled = false - return@launch - } - val recacheItems = I18n.translate("firmament.repo.cache") - ReloadProgressHud.reportProgress(recacheItems, 0, items.size) - ReloadProgressHud.isEnabled = true - var i = 0 - items.values.forEach { - it.asItemStack() // Rebuild cache - ReloadProgressHud.reportProgress(recacheItems, i++, items.size) - } - ReloadProgressHud.isEnabled = false + val newScope = + CoroutineScope( + Firmament.coroutineScope.coroutineContext + + SupervisorJob(Firmament.globalJob) + + Dispatchers.Default.limitedParallelism( + (Runtime.getRuntime().availableProcessors() / 4).coerceAtLeast(1) + ) + ) + val items = repository.items?.items + newScope.launch { + val items = items ?: return@launch + items.values.chunked(500).map { chunk -> + async { + chunk.forEach { + it.asItemStack() // Rebuild cache + } + } + }.awaitAll() } + itemRecacheScope = newScope } fun coinItem(coinAmount: Int): ItemStack { @@ -249,7 +289,7 @@ object ItemCache : IReloadable { "http://textures.minecraft.net/texture/7b951fed6a7b2cbc2036916dec7a46c4a56481564d14f945b6ebc03382766d3b" } val itemStack = ItemStack(Items.PLAYER_HEAD) - itemStack.setCustomName(Text.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins")) + itemStack.setCustomName(Component.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins")) itemStack.setSkullOwner(uuid, texture) return itemStack } @@ -263,10 +303,10 @@ object ItemCache : IReloadable { } -operator fun NbtCompound.set(key: String, value: String) { +operator fun CompoundTag.set(key: String, value: String) { putString(key, value) } -operator fun NbtCompound.set(key: String, value: NbtElement) { +operator fun CompoundTag.set(key: String, value: Tag) { put(key, value) } |
