aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/repo/ItemCache.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/repo/ItemCache.kt')
-rw-r--r--src/main/kotlin/repo/ItemCache.kt212
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)
}