From d4410a67fb43cf467194b67552cdf4b85c6753bd Mon Sep 17 00:00:00 2001 From: nea Date: Mon, 12 Jun 2023 17:46:41 +0200 Subject: Add crafting overlay --- TODO.txt | 10 +++- .../moe/nea/firmament/features/FeatureManager.kt | 2 + .../features/inventory/CraftingOverlay.kt | 66 ++++++++++++++++++++++ .../moe/nea/firmament/rei/FirmamentReiPlugin.kt | 19 ++++++- .../moe/nea/firmament/rei/SBItemEntryDefinition.kt | 19 ++++++- .../kotlin/moe/nea/firmament/util/SkyblockId.kt | 28 ++++++--- 6 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt diff --git a/TODO.txt b/TODO.txt index 3146436..e037d1b 100644 --- a/TODO.txt +++ b/TODO.txt @@ -15,8 +15,6 @@ - Dwarven Mines - Experimentation Solver - Capes -- Dungeon Profit -- Dungeon Map Priority 2: - missing talismans / pets in pv @@ -33,7 +31,6 @@ Priority 2: Priority 3: - Item rarity halo - Zealot Counter using Combat XP popups -- Use REIs "Move Item" functionality to higlight slots - client sided stat tracker that does not need the api - skills - coins @@ -43,3 +40,10 @@ Priority 3: - and much more that i will add as i go along + +Dungeons (planned in another mod): +- Dungeon Profit +- Dungeon Map +- Dungeon waypoints +- Dungeon puzzle solvers +- Talk with the big D diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index dfbb5ed..e465349 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -23,6 +23,7 @@ import kotlinx.serialization.serializer import moe.nea.firmament.Firmament import moe.nea.firmament.features.debug.DeveloperFeatures import moe.nea.firmament.features.fishing.FishingWarning +import moe.nea.firmament.features.inventory.CraftingOverlay import moe.nea.firmament.features.inventory.SlotLocking import moe.nea.firmament.features.world.FairySouls import moe.nea.firmament.util.data.DataHolder @@ -49,6 +50,7 @@ object FeatureManager : DataHolder(serializer(), "feature loadFeature(FairySouls) loadFeature(FishingWarning) loadFeature(SlotLocking) + loadFeature(CraftingOverlay) if (Firmament.DEBUG) loadFeature(DeveloperFeatures) hasAutoloaded = true diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt new file mode 100644 index 0000000..31d2b23 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt @@ -0,0 +1,66 @@ +package moe.nea.firmament.features.inventory + +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen +import net.minecraft.item.ItemStack +import net.minecraft.util.Formatting +import moe.nea.firmament.events.SlotRenderEvents +import moe.nea.firmament.features.FirmamentFeature +import moe.nea.firmament.recipes.SBCraftingRecipe +import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry +import moe.nea.firmament.rei.SBItemEntryDefinition +import moe.nea.firmament.util.MC + +object CraftingOverlay : FirmamentFeature { + + private var screen: GenericContainerScreen? = null + private var recipe: SBCraftingRecipe? = null + private val craftingOverlayIndices = listOf( + 10, 11, 12, + 19, 20, 21, + 28, 29, 30, + ) + + + fun setOverlay(screen: GenericContainerScreen, recipe: SBCraftingRecipe) { + this.screen = screen + this.recipe = recipe + } + + override val name: String + get() = "Crafting Overlay" + override val identifier: String + get() = "crafting-overlay" + + override fun onLoad() { + SlotRenderEvents.After.subscribe { event -> + val slot = event.slot + val recipe = this.recipe ?: return@subscribe + if (slot.inventory != screen?.screenHandler?.inventory) return@subscribe + val recipeIndex = craftingOverlayIndices.indexOf(slot.index) + if (recipeIndex < 0) return@subscribe + val expectedItem = recipe.neuRecipe.inputs[recipeIndex] + val actualStack = slot.stack ?: ItemStack.EMPTY!! + val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value + if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.stackSize < expectedItem.amount) && expectedItem.amount.toInt() != 0) { + event.context.fill( + event.slot.x, + event.slot.y, + event.slot.x + 16, + event.slot.y + 16, + 0x80FF0000.toInt() + ) + } + if (!slot.hasStack()) { + val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value + event.context.drawItem(itemStack, event.slot.x, event.slot.y) + event.context.drawItemInSlot( + MC.font, + itemStack, + event.slot.x, + event.slot.y, + "${Formatting.RED}${expectedItem.amount.toInt()}" + ) + } + } + } +} diff --git a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt b/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt index def73fe..5016d96 100644 --- a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt +++ b/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt @@ -24,18 +24,22 @@ import me.shedaniel.rei.api.client.registry.display.DisplayRegistry import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry import me.shedaniel.rei.api.client.registry.entry.EntryRegistry import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry +import me.shedaniel.rei.api.client.registry.transfer.TransferHandler +import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry import me.shedaniel.rei.api.common.entry.EntryStack import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.item.ItemStack import net.minecraft.text.Text import net.minecraft.util.Identifier +import moe.nea.firmament.features.inventory.CraftingOverlay import moe.nea.firmament.recipes.SBCraftingRecipe import moe.nea.firmament.recipes.SBForgeRecipe -import moe.nea.firmament.repo.ItemCache.asItemStack import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.skyblockId +import moe.nea.firmament.util.unformattedString class FirmamentReiPlugin : REIClientPlugin { @@ -48,6 +52,19 @@ class FirmamentReiPlugin : REIClientPlugin { val SKYBLOCK_ITEM_TYPE_ID = Identifier("firmament", "skyblockitems") } + override fun registerTransferHandlers(registry: TransferHandlerRegistry) { + registry.register(TransferHandler { context -> + val screen = context.containerScreen + val display = context.display + if (display !is SBCraftingRecipe || screen !is GenericContainerScreen || screen.title?.unformattedString != "Craft Item") { + return@TransferHandler TransferHandler.Result.createNotApplicable() + } + if (context.isActuallyCrafting) + CraftingOverlay.setOverlay(screen, display) + return@TransferHandler TransferHandler.Result.createSuccessful() + }) + } + override fun registerEntryTypes(registry: EntryTypeRegistry) { registry.register(SKYBLOCK_ITEM_TYPE_ID, SBItemEntryDefinition) } diff --git a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt b/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt index 3d54d5f..eac7d01 100644 --- a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt +++ b/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt @@ -39,7 +39,10 @@ import moe.nea.firmament.repo.ItemCache 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.SkyblockId +import moe.nea.firmament.util.petData +import moe.nea.firmament.util.skyBlockId // TODO: add in extra data like pet info, into this structure data class PetData( @@ -47,6 +50,12 @@ data class PetData( val petId: String, val exp: Double, ) { + companion object { + fun fromHypixel(petInfo: HypixelPetInfo) = PetData( + petInfo.tier, petInfo.type, petInfo.exp, + ) + } + val levelData by lazy { ExpLadders.getExpLadder(petId, rarity).getPetLevel(exp) } } @@ -155,5 +164,13 @@ object SBItemEntryDefinition : EntryDefinition { fun getEntry(ingredient: NEUIngredient): EntryStack = getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount.toInt()) - + fun getEntry(stack: ItemStack): EntryStack = + getEntry( + SBItemStack( + stack.skyBlockId ?: SkyblockId.NULL, + RepoManager.getNEUItem(stack.skyBlockId ?: SkyblockId.NULL), + stack.count, + petData = stack.petData?.let { PetData.fromHypixel(it) } + ) + ) } diff --git a/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt b/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt index b3c0e9d..9923d7a 100644 --- a/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt +++ b/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt @@ -15,17 +15,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - +@file:UseSerializers(DashlessUUIDSerializer::class) package moe.nea.firmament.util import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.Rarity +import java.util.UUID import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import net.minecraft.item.ItemStack import net.minecraft.nbt.NbtCompound import net.minecraft.util.Identifier +import moe.nea.firmament.util.json.DashlessUUIDSerializer /** * A skyblock item id, as used by the NEU repo. @@ -59,6 +62,7 @@ value class SkyblockId(val neuItem: String) { val COINS: SkyblockId = SkyblockId("SKYBLOCK_COIN") private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex() val NULL: SkyblockId = SkyblockId("null") + val PET_NULL: SkyblockId = SkyblockId("null_pet") } } @@ -68,6 +72,9 @@ val NEUItem.skyblockId get() = SkyblockId(skyblockItemId) data class HypixelPetInfo( val type: String, val tier: Rarity, + val exp: Double = 0.0, + val candyUsed: Int = 0, + val uuid: UUID? = null, ) { val skyblockId get() = SkyblockId("${type.uppercase()};${tier.ordinal}") } @@ -77,20 +84,23 @@ private val jsonparser = Json { ignoreUnknownKeys = true } val ItemStack.extraAttributes: NbtCompound get() = getOrCreateSubNbt("ExtraAttributes") +val ItemStack.petData: HypixelPetInfo? + get() { + val jsonString = extraAttributes.getString("petInfo") + if (jsonString.isNullOrBlank()) return null + return runCatching { jsonparser.decodeFromString(jsonString) } + .getOrElse { return null } + } + val ItemStack.skyBlockId: SkyblockId? get() { - when (val id = extraAttributes.getString("id")) { + return when (val id = extraAttributes.getString("id")) { "PET" -> { - val jsonString = extraAttributes.getString("petInfo") - if (jsonString.isNullOrBlank()) return null - val petInfo = - runCatching { jsonparser.decodeFromString(jsonString) } - .getOrElse { return null } - return petInfo.skyblockId + petData?.skyblockId ?: SkyblockId.PET_NULL } // TODO: RUNE, ENCHANTED_BOOK, PARTY_HAT_CRAB{,_ANIMATED}, ABICASE else -> { - return SkyblockId(id) + SkyblockId(id) } } } -- cgit