aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/firmament/repo
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament/repo')
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt28
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt50
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt94
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/HypixelStaticData.kt107
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt215
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt98
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt128
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt145
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt126
9 files changed, 0 insertions, 991 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt b/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt
deleted file mode 100644
index 91a6b50..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-
-package moe.nea.firmament.repo
-
-import io.github.moulberry.repo.IReloadable
-import io.github.moulberry.repo.NEURepository
-import io.github.moulberry.repo.data.NEURecipe
-import moe.nea.firmament.util.SkyblockId
-
-class BetterRepoRecipeCache(val essenceRecipeProvider: EssenceRecipeProvider) : IReloadable {
- var usages: Map<SkyblockId, Set<NEURecipe>> = mapOf()
- var recipes: Map<SkyblockId, Set<NEURecipe>> = mapOf()
-
- override fun reload(repository: NEURepository) {
- val usages = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>()
- val recipes = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>()
- val baseRecipes = repository.items.items.values
- .asSequence()
- .flatMap { it.recipes }
- val extraRecipes = essenceRecipeProvider.recipes
- (baseRecipes + extraRecipes)
- .forEach { recipe ->
- recipe.allInputs.forEach { usages.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
- recipe.allOutputs.forEach { recipes.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
- }
- this.usages = usages
- this.recipes = recipes
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt b/src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt
deleted file mode 100644
index 1833258..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-
-package moe.nea.firmament.repo
-
-import io.github.moulberry.repo.IReloadable
-import io.github.moulberry.repo.NEURepository
-import io.github.moulberry.repo.data.NEUIngredient
-import io.github.moulberry.repo.data.NEURecipe
-import moe.nea.firmament.util.SkyblockId
-
-class EssenceRecipeProvider : IReloadable {
- data class EssenceUpgradeRecipe(
- val itemId: SkyblockId,
- val starCountAfter: Int,
- val essenceCost: Int,
- val essenceType: String, // TODO: replace with proper type
- val extraItems: List<NEUIngredient>,
- ) : NEURecipe {
- val essenceIngredient= NEUIngredient.fromString("${essenceType}:$essenceCost")
- val allUpgradeComponents = listOf(essenceIngredient) + extraItems
-
- override fun getAllInputs(): Collection<NEUIngredient> {
- return listOf(NEUIngredient.fromString(itemId.neuItem + ":1")) + allUpgradeComponents
- }
-
- override fun getAllOutputs(): Collection<NEUIngredient> {
- return listOf(NEUIngredient.fromString(itemId.neuItem + ":1"))
- }
- }
-
- var recipes = listOf<EssenceUpgradeRecipe>()
- private set
-
- override fun reload(repository: NEURepository) {
- val recipes = mutableListOf<EssenceUpgradeRecipe>()
- for ((neuId, costs) in repository.constants.essenceCost.costs) {
- // TODO: add dungeonization costs. this is in repo, but not in the repo parser.
- for ((starCountAfter, essenceCost) in costs.essenceCosts.entries) {
- val items = costs.itemCosts[starCountAfter] ?: emptyList()
- recipes.add(
- EssenceUpgradeRecipe(
- SkyblockId(neuId),
- starCountAfter,
- essenceCost,
- "ESSENCE_" + costs.type.uppercase(), // how flimsy
- items.map { NEUIngredient.fromString(it) }))
- }
- }
- this.recipes = recipes
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt b/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt
deleted file mode 100644
index fbc9eb8..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-package moe.nea.firmament.repo
-
-import com.google.common.cache.CacheBuilder
-import com.google.common.cache.CacheLoader
-import io.github.moulberry.repo.IReloadable
-import io.github.moulberry.repo.NEURepository
-import io.github.moulberry.repo.constants.PetLevelingBehaviourOverride
-import io.github.moulberry.repo.data.Rarity
-
-object ExpLadders : IReloadable {
-
- data class PetLevel(
- val currentLevel: Int,
- val maxLevel: Int,
- val expRequiredForNextLevel: Long,
- val expRequiredForMaxLevel: Long,
- val expInCurrentLevel: Float,
- var expTotal: Float,
- ) {
- val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel
- }
-
- data class ExpLadder(
- val individualLevelCost: List<Long>,
- ) {
- val cumulativeLevelCost = individualLevelCost.runningFold(0F) { a, b -> a + b }.map { it.toLong() }
- fun getPetLevel(currentExp: Double): PetLevel {
- val currentOneIndexedLevel = cumulativeLevelCost.indexOfLast { it <= currentExp } + 1
- val expForNextLevel = if (currentOneIndexedLevel > individualLevelCost.size) { // Max leveled pet
- individualLevelCost.last()
- } else {
- individualLevelCost[currentOneIndexedLevel - 1]
- }
- val expInCurrentLevel =
- if (currentOneIndexedLevel >= cumulativeLevelCost.size)
- currentExp.toFloat() - cumulativeLevelCost.last()
- else
- (expForNextLevel - (cumulativeLevelCost[currentOneIndexedLevel] - currentExp.toFloat())).coerceAtLeast(
- 0F
- )
- return PetLevel(
- currentLevel = currentOneIndexedLevel,
- maxLevel = cumulativeLevelCost.size,
- expRequiredForNextLevel = expForNextLevel,
- expRequiredForMaxLevel = cumulativeLevelCost.last(),
- expInCurrentLevel = expInCurrentLevel,
- expTotal = currentExp.toFloat()
- )
- }
-
- fun getPetExpForLevel(level: Int): Long {
- if (level < 2) return 0L
- if (level >= cumulativeLevelCost.size) return cumulativeLevelCost.last()
- return cumulativeLevelCost[level - 1]
- }
- }
-
- private data class Key(val petIdWithoutRarity: String, val rarity: Rarity)
-
- private val expLadders = CacheBuilder.newBuilder()
- .build(object : CacheLoader<Key, ExpLadder>() {
- override fun load(key: Key): ExpLadder {
- val pld = RepoManager.neuRepo.constants.petLevelingData
- var exp = pld.petExpCostForLevel
- var offset = pld.petLevelStartOffset[key.rarity]!!
- var maxLevel = 100
- val override = pld.petLevelingBehaviourOverrides[key.petIdWithoutRarity]
- if (override != null) {
- maxLevel = override.maxLevel ?: maxLevel
- offset = override.petLevelStartOffset?.get(key.rarity) ?: offset
- when (override.petExpCostModifierType) {
- PetLevelingBehaviourOverride.PetExpModifierType.APPEND ->
- exp = exp + override.petExpCostModifier
-
- PetLevelingBehaviourOverride.PetExpModifierType.REPLACE ->
- exp = override.petExpCostModifier
-
- null -> {}
- }
- }
- return ExpLadder(exp.drop(offset).take(maxLevel - 1).map { it.toLong() })
- }
- })
-
- override fun reload(repository: NEURepository?) {
- expLadders.invalidateAll()
- }
-
- fun getExpLadder(petId: String, rarity: Rarity): ExpLadder {
- return expLadders.get(Key(petId, rarity))
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/HypixelStaticData.kt b/src/main/kotlin/moe/nea/firmament/repo/HypixelStaticData.kt
deleted file mode 100644
index 5c2a2fc..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/HypixelStaticData.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-package moe.nea.firmament.repo
-
-import io.ktor.client.call.body
-import io.ktor.client.request.get
-import org.apache.logging.log4j.LogManager
-import org.lwjgl.glfw.GLFW
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withTimeoutOrNull
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
-import kotlin.time.Duration.Companion.minutes
-import moe.nea.firmament.Firmament
-import moe.nea.firmament.apis.CollectionResponse
-import moe.nea.firmament.apis.CollectionSkillData
-import moe.nea.firmament.keybindings.IKeyBinding
-import moe.nea.firmament.util.SkyblockId
-import moe.nea.firmament.util.async.waitForInput
-
-object HypixelStaticData {
- private val logger = LogManager.getLogger("Firmament.HypixelStaticData")
- private val moulberryBaseUrl = "https://moulberry.codes"
- private val hypixelApiBaseUrl = "https://api.hypixel.net"
- var lowestBin: Map<SkyblockId, Double> = mapOf()
- private set
- var bazaarData: Map<SkyblockId, BazaarData> = mapOf()
- private set
- var collectionData: Map<String, CollectionSkillData> = mapOf()
- private set
-
- @Serializable
- data class BazaarData(
- @SerialName("product_id")
- val productId: SkyblockId.BazaarStock,
- @SerialName("quick_status")
- val quickStatus: BazaarStatus,
- )
-
- @Serializable
- data class BazaarStatus(
- val sellPrice: Double,
- val sellVolume: Long,
- val sellMovingWeek: Long,
- val sellOrders: Long,
- val buyPrice: Double,
- val buyVolume: Long,
- val buyMovingWeek: Long,
- val buyOrders: Long
- )
-
- @Serializable
- private data class BazaarResponse(
- val success: Boolean,
- val products: Map<SkyblockId.BazaarStock, BazaarData> = mapOf(),
- )
-
- fun getPriceOfItem(item: SkyblockId): Double? = bazaarData[item]?.quickStatus?.buyPrice ?: lowestBin[item]
-
-
- fun spawnDataCollectionLoop() {
- Firmament.coroutineScope.launch {
- logger.info("Updating collection data")
- updateCollectionData()
- }
- Firmament.coroutineScope.launch {
- while (true) {
- logger.info("Updating NEU prices")
- updatePrices()
- withTimeoutOrNull(10.minutes) { waitForInput(IKeyBinding.ofKeyCode(GLFW.GLFW_KEY_U)) }
- }
- }
- }
-
- private suspend fun updatePrices() {
- awaitAll(
- Firmament.coroutineScope.async { fetchBazaarPrices() },
- Firmament.coroutineScope.async { fetchPricesFromMoulberry() },
- )
- }
-
- private suspend fun fetchPricesFromMoulberry() {
- lowestBin = Firmament.httpClient.get("$moulberryBaseUrl/lowestbin.json")
- .body<Map<SkyblockId, Double>>()
- }
-
- private suspend fun fetchBazaarPrices() {
- val response = Firmament.httpClient.get("$hypixelApiBaseUrl/skyblock/bazaar").body<BazaarResponse>()
- if (!response.success) {
- logger.warn("Retrieved unsuccessful bazaar data")
- }
- bazaarData = response.products.mapKeys { it.key.toRepoId() }
- }
-
- private suspend fun updateCollectionData() {
- val response =
- Firmament.httpClient.get("$hypixelApiBaseUrl/resources/skyblock/collections").body<CollectionResponse>()
- if (!response.success) {
- logger.warn("Retrieved unsuccessful collection data")
- }
- collectionData = response.collections
- logger.info("Downloaded ${collectionData.values.sumOf { it.items.values.size }} collections")
- }
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt b/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt
deleted file mode 100644
index 08143be..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt
+++ /dev/null
@@ -1,215 +0,0 @@
-
-
-package moe.nea.firmament.repo
-
-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.launch
-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.nbt.NbtOps
-import net.minecraft.text.Text
-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.util.LegacyTagParser
-import moe.nea.firmament.util.MC
-import moe.nea.firmament.util.SkyblockId
-import moe.nea.firmament.util.appendLore
-import moe.nea.firmament.util.item.setCustomName
-import moe.nea.firmament.util.item.setSkullOwner
-import moe.nea.firmament.util.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
- }
-}
-
-
-operator fun NbtCompound.set(key: String, value: String) {
- putString(key, value)
-}
-
-operator fun NbtCompound.set(key: String, value: NbtElement) {
- put(key, value)
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt b/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt
deleted file mode 100644
index 770de85..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-
-package moe.nea.firmament.repo
-
-import io.github.moulberry.repo.IReloadable
-import io.github.moulberry.repo.NEURepository
-import io.github.moulberry.repo.data.NEUItem
-import java.util.NavigableMap
-import java.util.TreeMap
-import moe.nea.firmament.util.SkyblockId
-import moe.nea.firmament.util.removeColorCodes
-import moe.nea.firmament.util.skyblockId
-
-object ItemNameLookup : IReloadable {
-
- fun getItemNameChunks(name: String): Set<String> {
- return name.removeColorCodes().split(" ").filterTo(mutableSetOf()) { it.isNotBlank() }
- }
-
- 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
- }
-
- 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 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
- }
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt
deleted file mode 100644
index d674f23..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-
-
-package moe.nea.firmament.repo
-
-import io.ktor.client.call.body
-import io.ktor.client.request.get
-import io.ktor.client.statement.bodyAsChannel
-import io.ktor.utils.io.jvm.nio.copyTo
-import java.io.IOException
-import java.nio.file.Files
-import java.nio.file.Path
-import java.nio.file.StandardOpenOption
-import java.util.zip.ZipInputStream
-import kotlinx.coroutines.CoroutineName
-import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.withContext
-import kotlinx.serialization.Serializable
-import kotlin.io.path.createDirectories
-import kotlin.io.path.exists
-import kotlin.io.path.inputStream
-import kotlin.io.path.outputStream
-import kotlin.io.path.readText
-import kotlin.io.path.writeText
-import moe.nea.firmament.Firmament
-import moe.nea.firmament.Firmament.logger
-import moe.nea.firmament.util.iterate
-
-
-object RepoDownloadManager {
-
- val repoSavedLocation = Firmament.DATA_DIR.resolve("repo-extracted")
- val repoMetadataLocation = Firmament.DATA_DIR.resolve("loaded-repo-sha.txt")
-
- private fun loadSavedVersionHash(): String? =
- if (repoSavedLocation.exists()) {
- if (repoMetadataLocation.exists()) {
- try {
- repoMetadataLocation.readText().trim()
- } catch (e: IOException) {
- null
- }
- } else {
- null
- }
- } else null
-
- private fun saveVersionHash(versionHash: String) {
- latestSavedVersionHash = versionHash
- repoMetadataLocation.writeText(versionHash)
- }
-
- var latestSavedVersionHash: String? = loadSavedVersionHash()
- private set
-
- @Serializable
- private class GithubCommitsResponse(val sha: String)
-
- private suspend fun requestLatestGithubSha(): String? {
- if (RepoManager.Config.branch == "prerelease") {
- RepoManager.Config.branch = "master"
- }
- val response =
- Firmament.httpClient.get("https://api.github.com/repos/${RepoManager.Config.username}/${RepoManager.Config.reponame}/commits/${RepoManager.Config.branch}")
- if (response.status.value != 200) {
- return null
- }
- return response.body<GithubCommitsResponse>().sha
- }
-
- private suspend fun downloadGithubArchive(url: String): Path = withContext(IO) {
- val response = Firmament.httpClient.get(url)
- val targetFile = Files.createTempFile("firmament-repo", ".zip")
- val outputChannel = Files.newByteChannel(targetFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE)
- response.bodyAsChannel().copyTo(outputChannel)
- targetFile
- }
-
- /**
- * Downloads the latest repository from github, setting [latestSavedVersionHash].
- * @return true, if an update was performed, false, otherwise (no update needed, or wasn't able to complete update)
- */
- suspend fun downloadUpdate(force: Boolean): Boolean = withContext(CoroutineName("Repo Update Check")) {
- val latestSha = requestLatestGithubSha()
- if (latestSha == null) {
- logger.warn("Could not request github API to retrieve latest REPO sha.")
- return@withContext false
- }
- val currentSha = loadSavedVersionHash()
- if (latestSha != currentSha || force) {
- val requestUrl =
- "https://github.com/${RepoManager.Config.username}/${RepoManager.Config.reponame}/archive/$latestSha.zip"
- logger.info("Planning to upgrade repository from $currentSha to $latestSha from $requestUrl")
- val zipFile = downloadGithubArchive(requestUrl)
- logger.info("Download repository zip file to $zipFile. Deleting old repository")
- withContext(IO) { repoSavedLocation.toFile().deleteRecursively() }
- logger.info("Extracting new repository")
- withContext(IO) { extractNewRepository(zipFile) }
- logger.info("Repository loaded on disk.")
- saveVersionHash(latestSha)
- return@withContext true
- } else {
- logger.debug("Repository on latest sha $currentSha. Not performing update")
- return@withContext false
- }
- }
-
- private fun extractNewRepository(zipFile: Path) {
- repoSavedLocation.createDirectories()
- ZipInputStream(zipFile.inputStream()).use { cis ->
- while (true) {
- val entry = cis.nextEntry ?: break
- if (entry.isDirectory) continue
- val extractedLocation =
- repoSavedLocation.resolve(
- entry.name.substringAfter('/', missingDelimiterValue = "")
- )
- if (repoSavedLocation !in extractedLocation.iterate { it.parent }) {
- logger.error("Firmament detected an invalid zip file. This is a potential security risk, please report this in the Firmament discord.")
- throw RuntimeException("Firmament detected an invalid zip file. This is a potential security risk, please report this in the Firmament discord.")
- }
- extractedLocation.parent.createDirectories()
- extractedLocation.outputStream().use { cis.copyTo(it) }
- }
- }
- }
-
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt
deleted file mode 100644
index f0da397..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt
+++ /dev/null
@@ -1,145 +0,0 @@
-package moe.nea.firmament.repo
-
-import io.github.moulberry.repo.NEURepository
-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 net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
-import kotlinx.coroutines.launch
-import net.minecraft.client.MinecraftClient
-import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket
-import net.minecraft.text.Text
-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.rei.PetData
-import moe.nea.firmament.util.MinecraftDispatcher
-import moe.nea.firmament.util.SkyblockId
-
-object RepoManager {
- object Config : ManagedConfig("repo") {
- var username by string("username") { "NotEnoughUpdates" }
- var reponame by string("reponame") { "NotEnoughUpdates-REPO" }
- var branch by string("branch") { "master" }
- val autoUpdate by toggle("autoUpdate") { true }
- val reset by button("reset") {
- username = "NotEnoughUpdates"
- reponame = "NotEnoughUpdates-REPO"
- branch = "master"
- save()
- }
-
- val disableItemGroups by toggle("disable-item-groups") { true }
- val reload by button("reload") {
- save()
- RepoManager.reload()
- }
- val redownload by button("redownload") {
- save()
- RepoManager.launchAsyncUpdate(true)
- }
- }
-
- val currentDownloadedSha by RepoDownloadManager::latestSavedVersionHash
-
- 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)
-
- init {
- neuRepo.registerReloadListener(essenceRecipeProvider)
- neuRepo.registerReloadListener(recipeCache)
- }
-
- fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes }
-
- fun getRecipesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.recipes[skyblockId] ?: setOf()
- fun getUsagesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.usages[skyblockId] ?: setOf()
-
- private fun trySendClientboundUpdateRecipesPacket(): Boolean {
- return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes(
- SynchronizeRecipesS2CPacket(mutableListOf())
- ) != null
- }
-
- init {
- ClientTickEvents.START_WORLD_TICK.register(ClientTickEvents.StartWorldTick {
- if (recentlyFailedToUpdateItemList && trySendClientboundUpdateRecipesPacket())
- recentlyFailedToUpdateItemList = false
- })
- }
-
- fun getNEUItem(skyblockId: SkyblockId): NEUItem? = neuRepo.items.getItemBySkyblockId(skyblockId.neuItem)
-
- fun launchAsyncUpdate(force: Boolean = false) {
- Firmament.coroutineScope.launch {
- ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper boundy bar
- ItemCache.ReloadProgressHud.isEnabled = true
- try {
- RepoDownloadManager.downloadUpdate(force)
- ItemCache.ReloadProgressHud.reportProgress("Download complete", 1, 1)
- } finally {
- ItemCache.ReloadProgressHud.isEnabled = false
- }
- reload()
- }
- }
-
- fun reload() {
- try {
- ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk",
- 0,
- -1) // TODO: replace with a proper boundy bar
- ItemCache.ReloadProgressHud.isEnabled = true
- neuRepo.reload()
- } catch (exc: NEURepositoryException) {
- MinecraftClient.getInstance().player?.sendMessage(
- Text.literal("Failed to reload repository. This will result in some mod features not working.")
- )
- ItemCache.ReloadProgressHud.isEnabled = false
- exc.printStackTrace()
- }
- }
-
- fun initialize() {
- if (Config.autoUpdate) {
- launchAsyncUpdate()
- } else {
- reload()
- }
- }
-
- fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? {
- val parts = skyblockId.neuItem.split(";")
- if (parts.size != 2) {
- return null
- }
- val (petId, rarityIndex) = parts
- if (!rarityIndex.all { it.isDigit() }) {
- return null
- }
- val intIndex = rarityIndex.toInt()
- if (intIndex !in Rarity.values().indices) return null
- if (petId !in neuRepo.constants.petNumbers) return null
- return PetData(Rarity.values()[intIndex], petId, 0.0, true)
- }
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt
deleted file mode 100644
index f92fe4f..0000000
--- a/src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-
-package moe.nea.firmament.repo
-
-import java.io.InputStream
-import java.nio.file.Files
-import java.nio.file.Path
-import java.util.*
-import net.fabricmc.fabric.api.resource.ModResourcePack
-import net.fabricmc.loader.api.FabricLoader
-import net.fabricmc.loader.api.metadata.ModMetadata
-import kotlin.io.path.exists
-import kotlin.io.path.isRegularFile
-import kotlin.io.path.relativeTo
-import kotlin.streams.asSequence
-import net.minecraft.resource.AbstractFileResourcePack
-import net.minecraft.resource.InputSupplier
-import net.minecraft.resource.NamespaceResourceManager
-import net.minecraft.resource.Resource
-import net.minecraft.resource.ResourcePack
-import net.minecraft.resource.ResourcePackInfo
-import net.minecraft.resource.ResourcePackSource
-import net.minecraft.resource.ResourceType
-import net.minecraft.resource.metadata.ResourceMetadata
-import net.minecraft.resource.metadata.ResourceMetadataReader
-import net.minecraft.text.Text
-import net.minecraft.util.Identifier
-import net.minecraft.util.PathUtil
-import moe.nea.firmament.Firmament
-
-class RepoModResourcePack(val basePath: Path) : ModResourcePack {
- companion object {
- fun append(packs: MutableList<in ModResourcePack>) {
- Firmament.logger.info("Registering mod resource pack")
- packs.add(RepoModResourcePack(RepoDownloadManager.repoSavedLocation))
- }
-
- fun createResourceDirectly(identifier: Identifier): Optional<Resource> {
- val pack = RepoModResourcePack(RepoDownloadManager.repoSavedLocation)
- return Optional.of(
- Resource(
- pack,
- pack.open(ResourceType.CLIENT_RESOURCES, identifier) ?: return Optional.empty()
- ) {
- val base =
- pack.open(ResourceType.CLIENT_RESOURCES, identifier.withPath(identifier.path + ".mcmeta"))
- if (base == null)
- ResourceMetadata.NONE
- else
- NamespaceResourceManager.loadMetadata(base)
- }
- )
- }
- }
-
- override fun close() {
- }
-
- override fun openRoot(vararg segments: String): InputSupplier<InputStream>? {
- return getFile(segments)?.let { InputSupplier.create(it) }
- }
-
- fun getFile(segments: Array<out String>): Path? {
- PathUtil.validatePath(*segments)
- val path = segments.fold(basePath, Path::resolve)
- if (!path.isRegularFile()) return null
- return path
- }
-
- override fun open(type: ResourceType?, id: Identifier): InputSupplier<InputStream>? {
- if (type != ResourceType.CLIENT_RESOURCES) return null
- if (id.namespace != "neurepo") return null
- val file = getFile(id.path.split("/").toTypedArray())
- return file?.let { InputSupplier.create(it) }
- }
-
- override fun findResources(
- type: ResourceType?,
- namespace: String,
- prefix: String,
- consumer: ResourcePack.ResultConsumer
- ) {
- if (namespace != "neurepo") return
- if (type != ResourceType.CLIENT_RESOURCES) return
-
- val prefixPath = basePath.resolve(prefix)
- if (!prefixPath.exists())
- return
- Files.walk(prefixPath)
- .asSequence()
- .map { it.relativeTo(basePath) }
- .forEach {
- consumer.accept(Identifier.of("neurepo", it.toString()), InputSupplier.create(it))
- }
- }
-
- override fun getNamespaces(type: ResourceType?): Set<String> {
- if (type != ResourceType.CLIENT_RESOURCES) return emptySet()
- return setOf("neurepo")
- }
-
- override fun <T> parseMetadata(metaReader: ResourceMetadataReader<T>): T? {
- return AbstractFileResourcePack.parseMetadata(
- metaReader, """
-{
- "pack": {
- "pack_format": 12,
- "description": "NEU Repo Resources"
- }
-}
-""".trimIndent().byteInputStream()
- )
- }
-
- override fun getInfo(): ResourcePackInfo {
- return ResourcePackInfo("neurepo", Text.literal("NEU Repo"), ResourcePackSource.BUILTIN, Optional.empty())
- }
-
- override fun getFabricModMetadata(): ModMetadata {
- return FabricLoader.getInstance().getModContainer("firmament")
- .get().metadata
- }
-
- override fun createOverlay(overlay: String): ModResourcePack {
- return RepoModResourcePack(basePath.resolve(overlay))
- }
-}