diff options
Diffstat (limited to 'src/main/kotlin/repo')
-rw-r--r-- | src/main/kotlin/repo/ItemCache.kt | 342 | ||||
-rw-r--r-- | src/main/kotlin/repo/ItemNameLookup.kt | 155 | ||||
-rw-r--r-- | src/main/kotlin/repo/RepoManager.kt | 61 |
3 files changed, 296 insertions, 262 deletions
diff --git a/src/main/kotlin/repo/ItemCache.kt b/src/main/kotlin/repo/ItemCache.kt index c86934c..6fb2ab8 100644 --- a/src/main/kotlin/repo/ItemCache.kt +++ b/src/main/kotlin/repo/ItemCache.kt @@ -1,5 +1,3 @@ - - package moe.nea.firmament.repo import com.mojang.serialization.Dynamic @@ -30,186 +28,194 @@ 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.repo.RepoManager.initialize import moe.nea.firmament.util.LegacyTagParser import moe.nea.firmament.util.MC import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.TestUtil import moe.nea.firmament.util.mc.appendLore +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.mc.modifyLore import moe.nea.firmament.util.skyblockId object ItemCache : IReloadable { - private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap() - private val df = Schemas.getFixer() - val logger = LogManager.getLogger("${Firmament.logger.name}.ItemCache") - var isFlawless = true - private set - - private fun NEUItem.get10809CompoundTag(): NbtCompound = NbtCompound().apply { - put("tag", LegacyTagParser.parse(nbttag)) - putString("id", minecraftItemId) - putByte("Count", 1) - putShort("Damage", damage.toShort()) - } - - private fun NbtCompound.transformFrom10809ToModern(): NbtCompound? = - try { - df.update( - TypeReferences.ITEM_STACK, - Dynamic(NbtOps.INSTANCE, this), - -1, - SharedConstants.getGameVersion().saveVersion.id - ).value as NbtCompound - } catch (e: Exception) { - isFlawless = false - logger.error("Could not data fix up $this", e) - null - } - - fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack { - return ItemStack(Items.PAINTING).apply { - setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null")) - appendLore( - listOf( - Text.stringifiedTranslatable( - "firmament.repo.brokenitem", - (neuItem?.skyblockItemId ?: idHint) - ) - ) - ) - } - } - - private fun NEUItem.asItemStackNow(): ItemStack { - try { - val oldItemTag = get10809CompoundTag() - val modernItemTag = oldItemTag.transformFrom10809ToModern() - ?: return brokenItemStack(this) - val itemInstance = - ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this) - 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() - return brokenItemStack(this) - } - } - - fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack { - if (this == null) return brokenItemStack(null, idHint) - var s = cache[this.skyblockItemId] - if (s == null) { - s = asItemStackNow() - cache[this.skyblockItemId] = s - } - if (!loreReplacements.isNullOrEmpty()) { - s = s.copy()!! - s.applyLoreReplacements(loreReplacements) - s.setCustomName(s.name.applyLoreReplacements(loreReplacements)) - } - return s - } - - fun ItemStack.applyLoreReplacements(loreReplacements: Map<String, String>) { - modifyLore { lore -> - lore.map { - it.applyLoreReplacements(loreReplacements) - } - } - } - - fun Text.applyLoreReplacements(loreReplacements: Map<String, String>): Text { - assert(this.siblings.isEmpty()) - var string = this.string - loreReplacements.forEach { (find, replace) -> - string = string.replace("{$find}", replace) - } - return Text.literal(string).styled { this.style } - } - - fun NEUItem.getIdentifier() = skyblockId.identifier - - 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 - } - - @get:Bind("current") - var current: Double = 0.0 - - @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() - } - } - - override fun reload(repository: NEURepository) { - val j = job - if (j != null && j.isActive) { - j.cancel() - } - cache.clear() - isFlawless = true - - 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 - } - } - - fun coinItem(coinAmount: Int): ItemStack { - var uuid = UUID.fromString("2070f6cb-f5db-367a-acd0-64d39a7e5d1b") - var texture = - "http://textures.minecraft.net/texture/538071721cc5b4cd406ce431a13f86083a8973e1064d2f8897869930ee6e5237" - if (coinAmount >= 100000) { - uuid = UUID.fromString("94fa2455-2881-31fe-bb4e-e3e24d58dbe3") - texture = - "http://textures.minecraft.net/texture/c9b77999fed3a2758bfeaf0793e52283817bea64044bf43ef29433f954bb52f6" - } - if (coinAmount >= 10000000) { - uuid = UUID.fromString("0af8df1f-098c-3b72-ac6b-65d65fd0b668") - texture = - "http://textures.minecraft.net/texture/7b951fed6a7b2cbc2036916dec7a46c4a56481564d14f945b6ebc03382766d3b" - } - val itemStack = ItemStack(Items.PLAYER_HEAD) - itemStack.setCustomName(Text.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins")) - itemStack.setSkullOwner(uuid, texture) - return itemStack - } + private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap() + private val df = Schemas.getFixer() + val logger = LogManager.getLogger("${Firmament.logger.name}.ItemCache") + var isFlawless = true + private set + + private fun NEUItem.get10809CompoundTag(): NbtCompound = NbtCompound().apply { + put("tag", LegacyTagParser.parse(nbttag)) + putString("id", minecraftItemId) + putByte("Count", 1) + putShort("Damage", damage.toShort()) + } + + private fun NbtCompound.transformFrom10809ToModern(): NbtCompound? = + try { + df.update( + TypeReferences.ITEM_STACK, + Dynamic(NbtOps.INSTANCE, this), + -1, + SharedConstants.getGameVersion().saveVersion.id + ).value as NbtCompound + } catch (e: Exception) { + isFlawless = false + logger.error("Could not data fix up $this", e) + null + } + + fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack { + return ItemStack(Items.PAINTING).apply { + setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null")) + appendLore( + listOf( + Text.stringifiedTranslatable( + "firmament.repo.brokenitem", + (neuItem?.skyblockItemId ?: idHint) + ) + ) + ) + } + } + + private fun NEUItem.asItemStackNow(): ItemStack { + try { + val oldItemTag = get10809CompoundTag() + val modernItemTag = oldItemTag.transformFrom10809ToModern() + ?: return brokenItemStack(this) + val itemInstance = + ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this) + 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() + return brokenItemStack(this) + } + } + + fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack { + if (this == null) return brokenItemStack(null, idHint) + var s = cache[this.skyblockItemId] + if (s == null) { + s = asItemStackNow() + cache[this.skyblockItemId] = s + } + if (!loreReplacements.isNullOrEmpty()) { + s = s.copy()!! + s.applyLoreReplacements(loreReplacements) + s.setCustomName(s.name.applyLoreReplacements(loreReplacements)) + } + return s + } + + fun ItemStack.applyLoreReplacements(loreReplacements: Map<String, String>) { + modifyLore { lore -> + lore.map { + it.applyLoreReplacements(loreReplacements) + } + } + } + + fun Text.applyLoreReplacements(loreReplacements: Map<String, String>): Text { + assert(this.siblings.isEmpty()) + var string = this.string + loreReplacements.forEach { (find, replace) -> + string = string.replace("{$find}", replace) + } + return Text.literal(string).styled { this.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 + } + + @get:Bind("current") + var current: Double = 0.0 + + @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() + } + } + + override fun reload(repository: NEURepository) { + val j = job + if (j != null && j.isActive) { + j.cancel() + } + 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 + } + } + + fun coinItem(coinAmount: Int): ItemStack { + var uuid = UUID.fromString("2070f6cb-f5db-367a-acd0-64d39a7e5d1b") + var texture = + "http://textures.minecraft.net/texture/538071721cc5b4cd406ce431a13f86083a8973e1064d2f8897869930ee6e5237" + if (coinAmount >= 100000) { + uuid = UUID.fromString("94fa2455-2881-31fe-bb4e-e3e24d58dbe3") + texture = + "http://textures.minecraft.net/texture/c9b77999fed3a2758bfeaf0793e52283817bea64044bf43ef29433f954bb52f6" + } + if (coinAmount >= 10000000) { + uuid = UUID.fromString("0af8df1f-098c-3b72-ac6b-65d65fd0b668") + texture = + "http://textures.minecraft.net/texture/7b951fed6a7b2cbc2036916dec7a46c4a56481564d14f945b6ebc03382766d3b" + } + val itemStack = ItemStack(Items.PLAYER_HEAD) + itemStack.setCustomName(Text.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins")) + itemStack.setSkullOwner(uuid, texture) + return itemStack + } + + init { + if (TestUtil.isInTest) { + initialize() + } + } + } operator fun NbtCompound.set(key: String, value: String) { - putString(key, value) + putString(key, value) } operator fun NbtCompound.set(key: String, value: NbtElement) { - put(key, value) + put(key, value) } diff --git a/src/main/kotlin/repo/ItemNameLookup.kt b/src/main/kotlin/repo/ItemNameLookup.kt index 770de85..1250730 100644 --- a/src/main/kotlin/repo/ItemNameLookup.kt +++ b/src/main/kotlin/repo/ItemNameLookup.kt @@ -1,4 +1,3 @@ - package moe.nea.firmament.repo import io.github.moulberry.repo.IReloadable @@ -12,87 +11,91 @@ import moe.nea.firmament.util.skyblockId object ItemNameLookup : IReloadable { - fun getItemNameChunks(name: String): Set<String> { - return name.removeColorCodes().split(" ").filterTo(mutableSetOf()) { it.isNotBlank() } - } + fun getItemNameChunks(name: String): Set<String> { + return name.removeColorCodes().split(" ").filterTo(mutableSetOf()) { it.isNotBlank() } + } + + var nameMap: NavigableMap<String, out Set<SkyblockId>> = TreeMap() - var nameMap: NavigableMap<String, out Set<SkyblockId>> = TreeMap() + override fun reload(repository: NEURepository) { + val nameMap = TreeMap<String, MutableSet<SkyblockId>>() + repository.items.items.values.forEach { item -> + getAllNamesForItem(item).forEach { name -> + val chunks = getItemNameChunks(name) + chunks.forEach { chunk -> + val set = nameMap.getOrPut(chunk, ::mutableSetOf) + set.add(item.skyblockId) + } + } + } + this.nameMap = nameMap + } - override fun reload(repository: NEURepository) { - val nameMap = TreeMap<String, MutableSet<SkyblockId>>() - repository.items.items.values.forEach { item -> - getAllNamesForItem(item).forEach { name -> - val chunks = getItemNameChunks(name) - chunks.forEach { chunk -> - val set = nameMap.getOrPut(chunk, ::mutableSetOf) - set.add(item.skyblockId) - } - } - } - this.nameMap = nameMap - } + fun getAllNamesForItem(item: NEUItem): Set<String> { + val names = mutableSetOf<String>() + names.add(item.displayName) + if (item.displayName.contains("Enchanted Book")) { + val enchantName = item.lore.firstOrNull() + if (enchantName != null) { + names.add(enchantName) + } + } + return names + } - fun getAllNamesForItem(item: NEUItem): Set<String> { - val names = mutableSetOf<String>() - names.add(item.displayName) - if (item.displayName.contains("Enchanted Book")) { - val enchantName = item.lore.firstOrNull() - if (enchantName != null) { - names.add(enchantName) - } - } - return names - } + fun findItemCandidatesByName(name: String): MutableSet<SkyblockId> { + val candidates = mutableSetOf<SkyblockId>() + for (chunk in getItemNameChunks(name)) { + val set = nameMap[chunk] ?: emptySet() + candidates.addAll(set) + } + return candidates + } - fun findItemCandidatesByName(name: String): MutableSet<SkyblockId> { - val candidates = mutableSetOf<SkyblockId>() - for (chunk in getItemNameChunks(name)) { - val set = nameMap[chunk] ?: emptySet() - candidates.addAll(set) - } - return candidates - } + fun guessItemByName( + /** + * The display name of the item. Color codes will be ignored. + */ + name: String, + /** + * Whether the [name] may contain other text, such as reforges, master stars and such. + */ + mayBeMangled: Boolean + ): SkyblockId? { + val cleanName = name.removeColorCodes() + return findBestItemFromCandidates( + findItemCandidatesByName(cleanName), + cleanName, + true + ) + } - fun guessItemByName( - /** - * The display name of the item. Color codes will be ignored. - */ - name: String, - /** - * Whether the [name] may contain other text, such as reforges, master stars and such. - */ - mayBeMangled: Boolean - ): SkyblockId? { - val cleanName = name.removeColorCodes() - return findBestItemFromCandidates( - findItemCandidatesByName(cleanName), - cleanName, - true - ) - } + fun findBestItemFromCandidates( + candidates: Iterable<SkyblockId>, + name: String, mayBeMangled: Boolean + ): SkyblockId? { + val expectedClean = name.removeColorCodes() + var bestMatch: SkyblockId? = null + var bestMatchLength = -1 + for (candidate in candidates) { + val item = RepoManager.getNEUItem(candidate) ?: continue + for (name in getAllNamesForItem(item)) { + val actualClean = name.removeColorCodes() + val matches = if (mayBeMangled) expectedClean == actualClean + else expectedClean.contains(actualClean) + if (!matches) continue + if (actualClean.length > bestMatchLength) { + bestMatch = candidate + bestMatchLength = actualClean.length + } + } + } + return bestMatch + } - fun findBestItemFromCandidates( - candidates: Iterable<SkyblockId>, - name: String, mayBeMangled: Boolean - ): SkyblockId? { - val expectedClean = name.removeColorCodes() - var bestMatch: SkyblockId? = null - var bestMatchLength = -1 - for (candidate in candidates) { - val item = RepoManager.getNEUItem(candidate) ?: continue - for (name in getAllNamesForItem(item)) { - val actualClean = name.removeColorCodes() - val matches = if (mayBeMangled) expectedClean == actualClean - else expectedClean.contains(actualClean) - if (!matches) continue - if (actualClean.length > bestMatchLength) { - bestMatch = candidate - bestMatchLength = actualClean.length - } - } - } - return bestMatch - } + init { + RepoManager.initialize() + } } diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt index 725642e..dc39511 100644 --- a/src/main/kotlin/repo/RepoManager.kt +++ b/src/main/kotlin/repo/RepoManager.kt @@ -5,6 +5,7 @@ import io.github.moulberry.repo.NEURepositoryException import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.NEURecipe import io.github.moulberry.repo.data.Rarity +import java.nio.file.Path import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents import kotlinx.coroutines.launch import net.minecraft.client.MinecraftClient @@ -14,9 +15,11 @@ import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament.logger import moe.nea.firmament.events.ReloadRegistrationEvent import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.ErrorUtil 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.tr object RepoManager { @@ -49,28 +52,31 @@ object RepoManager { var recentlyFailedToUpdateItemList = false - val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply { - registerReloadListener(ItemCache) - registerReloadListener(ExpLadders) - registerReloadListener(ItemNameLookup) - ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this)) - registerReloadListener { - Firmament.coroutineScope.launch(MinecraftDispatcher) { - if (!trySendClientboundUpdateRecipesPacket()) { - logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.") - recentlyFailedToUpdateItemList = true + val essenceRecipeProvider = EssenceRecipeProvider() + val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider) + + fun makeNEURepository(path: Path): NEURepository { + return NEURepository.of(path).apply { + registerReloadListener(ItemCache) + registerReloadListener(ExpLadders) + registerReloadListener(ItemNameLookup) + ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this)) + registerReloadListener { + if (TestUtil.isInTest) return@registerReloadListener + Firmament.coroutineScope.launch(MinecraftDispatcher) { + if (!trySendClientboundUpdateRecipesPacket()) { + logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.") + recentlyFailedToUpdateItemList = true + } } } + registerReloadListener(essenceRecipeProvider) + registerReloadListener(recipeCache) } } - val essenceRecipeProvider = EssenceRecipeProvider() - val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider) - - init { - neuRepo.registerReloadListener(essenceRecipeProvider) - neuRepo.registerReloadListener(recipeCache) - } + lateinit var neuRepo: NEURepository + private set fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes } @@ -106,6 +112,11 @@ object RepoManager { } } + fun reloadForTest(from: Path) { + neuRepo = makeNEURepository(from) + reload() + } + fun reload() { try { ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk", @@ -114,16 +125,24 @@ object RepoManager { ItemCache.ReloadProgressHud.isEnabled = true neuRepo.reload() } catch (exc: NEURepositoryException) { + ErrorUtil.softError("Failed to reload repository", exc) MC.sendChat( tr("firmament.repo.reloadfail", "Failed to reload repository. This will result in some mod features not working.") ) ItemCache.ReloadProgressHud.isEnabled = false - exc.printStackTrace() } } + private var wasInitialized = false fun initialize() { + if (wasInitialized) return + wasInitialized = true + System.getProperty("firmament.testrepo")?.let { compTimeRepo -> + reloadForTest(Path.of(compTimeRepo)) + return + } + neuRepo = makeNEURepository(RepoDownloadManager.repoSavedLocation) if (Config.autoUpdate) { launchAsyncUpdate() } else { @@ -131,6 +150,12 @@ object RepoManager { } } + init { + if (TestUtil.isInTest) { + initialize() + } + } + fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? { val parts = skyblockId.neuItem.split(";") if (parts.size != 2) { |