From c7143936d7a1bf3ae49362049541b2d23b11ab8c Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Wed, 24 Jul 2024 02:22:30 +0200 Subject: Add essence upgrade recipes --- .../moe/nea/firmament/rei/FirmamentReiPlugin.kt | 6 ++ .../moe/nea/firmament/rei/SBItemEntryDefinition.kt | 42 +++++++++++++- .../rei/SkyblockCraftingRecipeDynamicGenerator.kt | 4 ++ .../rei/recipes/SBEssenceUpgradeRecipe.kt | 67 ++++++++++++++++++++++ .../nea/firmament/repo/BetterRepoRecipeCache.kt | 33 +++++++++++ .../nea/firmament/repo/EssenceRecipeProvider.kt | 54 +++++++++++++++++ .../moe/nea/firmament/repo/RepoDownloadManager.kt | 29 ++++++---- .../kotlin/moe/nea/firmament/repo/RepoManager.kt | 16 ++++-- .../moe/nea/firmament/util/item/NbtItemData.kt | 5 +- src/main/kotlin/moe/nea/firmament/util/textutil.kt | 3 +- 10 files changed, 240 insertions(+), 19 deletions(-) create mode 100644 src/main/kotlin/moe/nea/firmament/rei/recipes/SBEssenceUpgradeRecipe.kt create mode 100644 src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt create mode 100644 src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt (limited to 'src/main/kotlin') diff --git a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt b/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt index 86ad98b..b955350 100644 --- a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt +++ b/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt @@ -31,6 +31,7 @@ import moe.nea.firmament.events.HandledScreenPushREIEvent import moe.nea.firmament.features.inventory.CraftingOverlay import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen import moe.nea.firmament.rei.recipes.SBCraftingRecipe +import moe.nea.firmament.rei.recipes.SBEssenceUpgradeRecipe import moe.nea.firmament.rei.recipes.SBForgeRecipe import moe.nea.firmament.rei.recipes.SBKatRecipe import moe.nea.firmament.rei.recipes.SBMobDropRecipe @@ -72,6 +73,7 @@ class FirmamentReiPlugin : REIClientPlugin { registry.add(SBForgeRecipe.Category) registry.add(SBMobDropRecipe.Category) registry.add(SBKatRecipe.Category) + registry.add(SBEssenceUpgradeRecipe.Category) } override fun registerExclusionZones(zones: ExclusionZones) { @@ -92,6 +94,10 @@ class FirmamentReiPlugin : REIClientPlugin { registry.registerDisplayGenerator( SBKatRecipe.Category.categoryIdentifier, SkyblockKatRecipeDynamicGenerator) + registry.registerDisplayGenerator( + SBEssenceUpgradeRecipe.Category.categoryIdentifier, + SkyblockEssenceRecipeDynamicGenerator + ) } override fun registerCollapsibleEntries(registry: CollapsibleEntryRegistry) { diff --git a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt b/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt index 3897d01..19b26c5 100644 --- a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt +++ b/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt @@ -22,6 +22,7 @@ import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes import net.minecraft.item.ItemStack import net.minecraft.registry.tag.TagKey import net.minecraft.text.Text +import net.minecraft.util.Formatting import net.minecraft.util.Identifier import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry import moe.nea.firmament.repo.ExpLadders @@ -30,10 +31,13 @@ import moe.nea.firmament.repo.ItemCache.asItemStack import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.FirmFormatters import moe.nea.firmament.util.HypixelPetInfo +import moe.nea.firmament.util.LegacyFormattingCode import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.appendLore +import moe.nea.firmament.util.item.displayNameAccordingToNbt import moe.nea.firmament.util.petData import moe.nea.firmament.util.skyBlockId +import moe.nea.firmament.util.withColor // TODO: add in extra data like pet info, into this structure data class PetData( @@ -46,6 +50,7 @@ data class PetData( fun fromHypixel(petInfo: HypixelPetInfo) = PetData( petInfo.tier, petInfo.type, petInfo.exp, ) + fun forLevel(petId: String, rarity: Rarity, level: Int) = PetData( rarity, petId, ExpLadders.getExpLadder(petId, rarity).getPetExpForLevel(level).toDouble() ) @@ -60,6 +65,8 @@ data class SBItemStack( private var stackSize: Int, private var petData: PetData?, val extraLore: List = emptyList(), + // TODO: grab this star data from nbt if possible + val stars: Int = 0, ) { fun getStackSize() = stackSize @@ -67,6 +74,7 @@ data class SBItemStack( this.stackSize = stackSize this.itemStack_ = null } + fun getPetData() = petData fun setPetData(petData: PetData?) { this.petData = petData @@ -132,12 +140,42 @@ data class SBItemStack( injectReplacementDataForPets(replacementData) return@run neuItem.asItemStack(idHint = skyblockId, replacementData).copyWithCount(stackSize) .also { it.appendLore(extraLore) } + .also { enhanceStatsByStars(it, stars) } } if (itemStack_ == null) itemStack_ = itemStack return itemStack } + + private fun starString(stars: Int): Text { + if (stars <= 0) return Text.empty() + val tiers = listOf( + LegacyFormattingCode.GOLD, + LegacyFormattingCode.LIGHT_PURPLE, + LegacyFormattingCode.AQUA, + ) + val maxStars = 5 + if (stars > tiers.size * maxStars) return Text.literal(" ${stars}✪").withColor(Formatting.RED) + val starBaseTier = (stars - 1) / maxStars + val starBaseColor = tiers[starBaseTier] + val starsInCurrentTier = stars - starBaseTier * maxStars + val starString = Text.literal(" " + "✪".repeat(starsInCurrentTier)).withColor(starBaseColor.modern) + if (starBaseTier > 0) { + val starLastTier = tiers[starBaseTier - 1] + val starsInLastTier = 5 - starsInCurrentTier + starString.append(Text.literal("✪".repeat(starsInLastTier)).withColor(starLastTier.modern)) + } + return starString + } + + private fun enhanceStatsByStars(itemStack: ItemStack, stars: Int) { + if (stars == 0) return + // TODO: increase stats and add the star level into the nbt data so star displays work + itemStack.displayNameAccordingToNbt = itemStack.displayNameAccordingToNbt.copy() + .append(starString(stars)) + } + fun asImmutableItemStack(): ItemStack { return itemStack } @@ -179,11 +217,11 @@ object SBItemEntryDefinition : EntryDefinition { } override fun wildcard(entry: EntryStack?, value: SBItemStack): SBItemStack { - return value.copy(stackSize = 1) + return value.copy(stackSize = 1, petData = null, stars = 0, extraLore = listOf()) } override fun normalize(entry: EntryStack?, value: SBItemStack): SBItemStack { - return value.copy(stackSize = 1) + return wildcard(entry, value) } override fun copy(entry: EntryStack?, value: SBItemStack): SBItemStack { diff --git a/src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt b/src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt index ead2119..864a5c7 100644 --- a/src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt +++ b/src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt @@ -18,9 +18,11 @@ import me.shedaniel.rei.api.client.view.ViewSearchBuilder import me.shedaniel.rei.api.common.display.Display import me.shedaniel.rei.api.common.entry.EntryStack import moe.nea.firmament.rei.recipes.SBCraftingRecipe +import moe.nea.firmament.rei.recipes.SBEssenceUpgradeRecipe import moe.nea.firmament.rei.recipes.SBForgeRecipe import moe.nea.firmament.rei.recipes.SBKatRecipe import moe.nea.firmament.rei.recipes.SBMobDropRecipe +import moe.nea.firmament.repo.EssenceRecipeProvider import moe.nea.firmament.repo.RepoManager @@ -35,6 +37,8 @@ val SkyblockMobDropRecipeDynamicGenerator = val SkyblockKatRecipeDynamicGenerator = neuDisplayGenerator { SBKatRecipe(it) } +val SkyblockEssenceRecipeDynamicGenerator = + neuDisplayGenerator { SBEssenceUpgradeRecipe(it) } inline fun neuDisplayGenerator(crossinline mapper: (T) -> D) = object : DynamicDisplayGenerator { diff --git a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBEssenceUpgradeRecipe.kt b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBEssenceUpgradeRecipe.kt new file mode 100644 index 0000000..fbf0687 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBEssenceUpgradeRecipe.kt @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.rei.recipes + +import me.shedaniel.math.Point +import me.shedaniel.math.Rectangle +import me.shedaniel.rei.api.client.gui.Renderer +import me.shedaniel.rei.api.client.gui.widgets.Widget +import me.shedaniel.rei.api.client.gui.widgets.Widgets +import me.shedaniel.rei.api.client.registry.display.DisplayCategory +import me.shedaniel.rei.api.common.category.CategoryIdentifier +import net.minecraft.text.Text +import moe.nea.firmament.Firmament +import moe.nea.firmament.rei.SBItemEntryDefinition +import moe.nea.firmament.rei.SBItemStack +import moe.nea.firmament.repo.EssenceRecipeProvider +import moe.nea.firmament.util.SkyblockId + +class SBEssenceUpgradeRecipe(override val neuRecipe: EssenceRecipeProvider.EssenceUpgradeRecipe) : SBRecipe() { + object Category : DisplayCategory { + override fun getCategoryIdentifier(): CategoryIdentifier = + CategoryIdentifier.of(Firmament.MOD_ID, "essence_upgrade") + + override fun getTitle(): Text { + return Text.literal("Essence Upgrades") + } + + override fun getIcon(): Renderer { + return SBItemEntryDefinition.getEntry(SkyblockId("ESSENCE_WITHER")) + } + + override fun setupDisplay(display: SBEssenceUpgradeRecipe, bounds: Rectangle): List { + val recipe = display.neuRecipe + val list = mutableListOf() + list.add(Widgets.createRecipeBase(bounds)) + list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 - 18 / 2)) + .markInput() + .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter - 1)))) + list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 + 18 / 2)) + .markInput() + .entry(SBItemEntryDefinition.getEntry(recipe.essenceIngredient))) + list.add(Widgets.createSlot(Point(bounds.maxX - 12 - 16, bounds.centerY - 8)) + .markOutput() + .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter)))) + val extraItems = recipe.extraItems + list.add(Widgets.createArrow(Point(bounds.centerX - 24 / 2, + if (extraItems.isEmpty()) bounds.centerY - 17 / 2 + else bounds.centerY + 18 / 2))) + for ((index, item) in extraItems.withIndex()) { + list.add(Widgets.createSlot( + Point(bounds.centerX - extraItems.size * 16 / 2 - 2 / 2 + index * 18, + bounds.centerY - 18 / 2)) + .markInput() + .entry(SBItemEntryDefinition.getEntry(item))) + } + return list + } + } + + override fun getCategoryIdentifier(): CategoryIdentifier<*> { + return Category.categoryIdentifier + } +} diff --git a/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt b/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt new file mode 100644 index 0000000..9ccf72d --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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> = mapOf() + var recipes: Map> = mapOf() + + override fun reload(repository: NEURepository) { + val usages = mutableMapOf>() + val recipes = mutableMapOf>() + 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 new file mode 100644 index 0000000..09bc49c --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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, + ) : NEURecipe { + val essenceIngredient= NEUIngredient.fromString("${essenceType}:$essenceCost") + val allUpgradeComponents = listOf(essenceIngredient) + extraItems + + override fun getAllInputs(): Collection { + return listOf(NEUIngredient.fromString(itemId.neuItem + ":1")) + allUpgradeComponents + } + + override fun getAllOutputs(): Collection { + return listOf(NEUIngredient.fromString(itemId.neuItem + ":1")) + } + } + + var recipes = listOf() + private set + + override fun reload(repository: NEURepository) { + val recipes = mutableListOf() + for ((neuId, costs) in repository.constants.essenceCost.costs) { + 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/RepoDownloadManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt index 1c27a97..afd9b9f 100644 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt +++ b/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt @@ -1,28 +1,34 @@ /* * SPDX-FileCopyrightText: 2023 Linnea Gräf + * SPDX-FileCopyrightText: 2024 Linnea Gräf * * SPDX-License-Identifier: GPL-3.0-or-later */ package moe.nea.firmament.repo -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.utils.io.jvm.nio.* +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 -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 kotlin.io.path.* object RepoDownloadManager { @@ -55,6 +61,9 @@ object RepoDownloadManager { 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) { diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt index f556a8b..179b720 100644 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt +++ b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2023 Linnea Gräf + * SPDX-FileCopyrightText: 2024 Linnea Gräf * * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -28,12 +29,12 @@ object RepoManager { object Config : ManagedConfig("repo") { var username by string("username") { "NotEnoughUpdates" } var reponame by string("reponame") { "NotEnoughUpdates-REPO" } - var branch by string("branch") { "prerelease" } + var branch by string("branch") { "master" } val autoUpdate by toggle("autoUpdate") { true } val reset by button("reset") { username = "NotEnoughUpdates" reponame = "NotEnoughUpdates-REPO" - branch = "prerelease" + branch = "master" save() } @@ -66,12 +67,17 @@ object RepoManager { } } - private val recipeCache = NEURecipeCache.forRepo(neuRepo) + 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 = recipeCache.recipes[skyblockId.neuItem] ?: setOf() - fun getUsagesFor(skyblockId: SkyblockId): Set = recipeCache.usages[skyblockId.neuItem] ?: setOf() + fun getRecipesFor(skyblockId: SkyblockId): Set = recipeCache.recipes[skyblockId] ?: setOf() + fun getUsagesFor(skyblockId: SkyblockId): Set = recipeCache.usages[skyblockId] ?: setOf() private fun trySendClientboundUpdateRecipesPacket(): Boolean { return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes( diff --git a/src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt b/src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt index ef22325..c33c47f 100644 --- a/src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt +++ b/src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt @@ -18,8 +18,11 @@ var ItemStack.loreAccordingToNbt set(DataComponentTypes.LORE, LoreComponent(value)) } -val ItemStack.displayNameAccordingToNbt +var ItemStack.displayNameAccordingToNbt: Text get() = get(DataComponentTypes.CUSTOM_NAME) ?: get(DataComponentTypes.ITEM_NAME) ?: item.name + set(value) { + set(DataComponentTypes.CUSTOM_NAME, value) + } fun ItemStack.setCustomName(text: Text) { set(DataComponentTypes.CUSTOM_NAME, text) diff --git a/src/main/kotlin/moe/nea/firmament/util/textutil.kt b/src/main/kotlin/moe/nea/firmament/util/textutil.kt index 5f9379a..38b7daf 100644 --- a/src/main/kotlin/moe/nea/firmament/util/textutil.kt +++ b/src/main/kotlin/moe/nea/firmament/util/textutil.kt @@ -9,6 +9,7 @@ package moe.nea.firmament.util import net.minecraft.text.MutableText import net.minecraft.text.PlainTextContent +import net.minecraft.text.Style import net.minecraft.text.Text import net.minecraft.text.TranslatableTextContent import net.minecraft.util.Formatting @@ -98,7 +99,7 @@ val Text.unformattedString: String get() = string.removeColorCodes() -fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting) } +fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting).withItalic(false) } fun Text.transformEachRecursively(function: (Text) -> Text): Text { val c = this.content -- cgit