diff options
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament/repo')
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)) - } -} |